Commit 2d59e5ca8c7113ad91452f0f9259a4b55ee90323
Committed by
David S. Miller
1 parent
e54cbc1f91
[NETFILTER]: nf_nat: use extension infrastructure
Signed-off-by: Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 6 changed files with 73 additions and 36 deletions Side-by-side Diff
include/net/netfilter/nf_conntrack.h
... | ... | @@ -278,23 +278,6 @@ |
278 | 278 | extern void |
279 | 279 | nf_conntrack_unregister_cache(u_int32_t features); |
280 | 280 | |
281 | -/* valid combinations: | |
282 | - * basic: nf_conn, nf_conn .. nf_conn_help | |
283 | - * nat: nf_conn .. nf_conn_nat, nf_conn .. nf_conn_nat .. nf_conn help | |
284 | - */ | |
285 | -#ifdef CONFIG_NF_NAT_NEEDED | |
286 | -#include <net/netfilter/nf_nat.h> | |
287 | -static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) | |
288 | -{ | |
289 | - unsigned int offset = sizeof(struct nf_conn); | |
290 | - | |
291 | - if (!(ct->features & NF_CT_F_NAT)) | |
292 | - return NULL; | |
293 | - | |
294 | - offset = ALIGN(offset, __alignof__(struct nf_conn_nat)); | |
295 | - return (struct nf_conn_nat *) ((void *)ct + offset); | |
296 | -} | |
297 | -#endif /* CONFIG_NF_NAT_NEEDED */ | |
298 | 281 | #endif /* __KERNEL__ */ |
299 | 282 | #endif /* _NF_CONNTRACK_H */ |
include/net/netfilter/nf_conntrack_extend.h
... | ... | @@ -6,10 +6,12 @@ |
6 | 6 | enum nf_ct_ext_id |
7 | 7 | { |
8 | 8 | NF_CT_EXT_HELPER, |
9 | + NF_CT_EXT_NAT, | |
9 | 10 | NF_CT_EXT_NUM, |
10 | 11 | }; |
11 | 12 | |
12 | 13 | #define NF_CT_EXT_HELPER_TYPE struct nf_conn_help |
14 | +#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat | |
13 | 15 | |
14 | 16 | /* Extensions: optional stuff which isn't permanently in struct. */ |
15 | 17 | struct nf_ct_ext { |
include/net/netfilter/nf_nat.h
... | ... | @@ -52,6 +52,7 @@ |
52 | 52 | #ifdef __KERNEL__ |
53 | 53 | #include <linux/list.h> |
54 | 54 | #include <linux/netfilter/nf_conntrack_pptp.h> |
55 | +#include <net/netfilter/nf_conntrack_extend.h> | |
55 | 56 | |
56 | 57 | struct nf_conn; |
57 | 58 | |
... | ... | @@ -88,6 +89,11 @@ |
88 | 89 | /* Is this tuple already taken? (not by us)*/ |
89 | 90 | extern int nf_nat_used_tuple(const struct nf_conntrack_tuple *tuple, |
90 | 91 | const struct nf_conn *ignored_conntrack); |
92 | + | |
93 | +static inline struct nf_conn_nat *nfct_nat(const struct nf_conn *ct) | |
94 | +{ | |
95 | + return nf_ct_ext_find(ct, NF_CT_EXT_NAT); | |
96 | +} | |
91 | 97 | |
92 | 98 | extern int nf_nat_module_is_loaded; |
93 | 99 |
net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
net/ipv4/netfilter/nf_nat_core.c
... | ... | @@ -297,11 +297,21 @@ |
297 | 297 | unsigned int hooknum) |
298 | 298 | { |
299 | 299 | struct nf_conntrack_tuple curr_tuple, new_tuple; |
300 | - struct nf_conn_nat *nat = nfct_nat(ct); | |
301 | - struct nf_nat_info *info = &nat->info; | |
300 | + struct nf_conn_nat *nat; | |
301 | + struct nf_nat_info *info; | |
302 | 302 | int have_to_hash = !(ct->status & IPS_NAT_DONE_MASK); |
303 | 303 | enum nf_nat_manip_type maniptype = HOOK2MANIP(hooknum); |
304 | 304 | |
305 | + /* nat helper or nfctnetlink also setup binding */ | |
306 | + nat = nfct_nat(ct); | |
307 | + if (!nat) { | |
308 | + nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | |
309 | + if (nat == NULL) { | |
310 | + DEBUGP("failed to add NAT extension\n"); | |
311 | + return NF_ACCEPT; | |
312 | + } | |
313 | + } | |
314 | + | |
305 | 315 | NF_CT_ASSERT(hooknum == NF_IP_PRE_ROUTING || |
306 | 316 | hooknum == NF_IP_POST_ROUTING || |
307 | 317 | hooknum == NF_IP_LOCAL_IN || |
... | ... | @@ -338,6 +348,8 @@ |
338 | 348 | |
339 | 349 | srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); |
340 | 350 | write_lock_bh(&nf_nat_lock); |
351 | + /* nf_conntrack_alter_reply might re-allocate exntension aera */ | |
352 | + info = &nfct_nat(ct)->info; | |
341 | 353 | info->ct = ct; |
342 | 354 | list_add(&info->bysource, &bysource[srchash]); |
343 | 355 | write_unlock_bh(&nf_nat_lock); |
344 | 356 | |
345 | 357 | |
346 | 358 | |
... | ... | @@ -592,17 +604,52 @@ |
592 | 604 | EXPORT_SYMBOL_GPL(nf_nat_port_range_to_nfattr); |
593 | 605 | #endif |
594 | 606 | |
607 | +static void nf_nat_move_storage(struct nf_conn *conntrack, void *old) | |
608 | +{ | |
609 | + struct nf_conn_nat *new_nat = nf_ct_ext_find(conntrack, NF_CT_EXT_NAT); | |
610 | + struct nf_conn_nat *old_nat = (struct nf_conn_nat *)old; | |
611 | + struct nf_conn *ct = old_nat->info.ct; | |
612 | + unsigned int srchash; | |
613 | + | |
614 | + if (!(ct->status & IPS_NAT_DONE_MASK)) | |
615 | + return; | |
616 | + | |
617 | + srchash = hash_by_src(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); | |
618 | + | |
619 | + write_lock_bh(&nf_nat_lock); | |
620 | + list_replace(&old_nat->info.bysource, &new_nat->info.bysource); | |
621 | + new_nat->info.ct = ct; | |
622 | + write_unlock_bh(&nf_nat_lock); | |
623 | +} | |
624 | + | |
625 | +struct nf_ct_ext_type nat_extend = { | |
626 | + .len = sizeof(struct nf_conn_nat), | |
627 | + .align = __alignof__(struct nf_conn_nat), | |
628 | + .move = nf_nat_move_storage, | |
629 | + .id = NF_CT_EXT_NAT, | |
630 | + .flags = NF_CT_EXT_F_PREALLOC, | |
631 | +}; | |
632 | + | |
595 | 633 | static int __init nf_nat_init(void) |
596 | 634 | { |
597 | 635 | size_t i; |
636 | + int ret; | |
598 | 637 | |
638 | + ret = nf_ct_extend_register(&nat_extend); | |
639 | + if (ret < 0) { | |
640 | + printk(KERN_ERR "nf_nat_core: Unable to register extension\n"); | |
641 | + return ret; | |
642 | + } | |
643 | + | |
599 | 644 | /* Leave them the same for the moment. */ |
600 | 645 | nf_nat_htable_size = nf_conntrack_htable_size; |
601 | 646 | |
602 | 647 | /* One vmalloc for both hash tables */ |
603 | 648 | bysource = vmalloc(sizeof(struct list_head) * nf_nat_htable_size); |
604 | - if (!bysource) | |
605 | - return -ENOMEM; | |
649 | + if (!bysource) { | |
650 | + ret = -ENOMEM; | |
651 | + goto cleanup_extend; | |
652 | + } | |
606 | 653 | |
607 | 654 | /* Sew in builtin protocols. */ |
608 | 655 | write_lock_bh(&nf_nat_lock); |
... | ... | @@ -626,6 +673,10 @@ |
626 | 673 | |
627 | 674 | l3proto = nf_ct_l3proto_find_get((u_int16_t)AF_INET); |
628 | 675 | return 0; |
676 | + | |
677 | + cleanup_extend: | |
678 | + nf_ct_extend_unregister(&nat_extend); | |
679 | + return ret; | |
629 | 680 | } |
630 | 681 | |
631 | 682 | /* Clear NAT section of all conntracks, in case we're loaded again. */ |
... | ... | @@ -647,6 +698,7 @@ |
647 | 698 | synchronize_rcu(); |
648 | 699 | vfree(bysource); |
649 | 700 | nf_ct_l3proto_put(l3proto); |
701 | + nf_ct_extend_unregister(&nat_extend); | |
650 | 702 | } |
651 | 703 | |
652 | 704 | MODULE_LICENSE("GPL"); |
net/ipv4/netfilter/nf_nat_standalone.c
... | ... | @@ -19,6 +19,7 @@ |
19 | 19 | |
20 | 20 | #include <net/netfilter/nf_conntrack.h> |
21 | 21 | #include <net/netfilter/nf_conntrack_core.h> |
22 | +#include <net/netfilter/nf_conntrack_extend.h> | |
22 | 23 | #include <net/netfilter/nf_nat.h> |
23 | 24 | #include <net/netfilter/nf_nat_rule.h> |
24 | 25 | #include <net/netfilter/nf_nat_protocol.h> |
... | ... | @@ -113,8 +114,13 @@ |
113 | 114 | return NF_ACCEPT; |
114 | 115 | |
115 | 116 | nat = nfct_nat(ct); |
116 | - if (!nat) | |
117 | - return NF_ACCEPT; | |
117 | + if (!nat) { | |
118 | + nat = nf_ct_ext_add(ct, NF_CT_EXT_NAT, GFP_ATOMIC); | |
119 | + if (nat == NULL) { | |
120 | + DEBUGP("failed to add NAT extension\n"); | |
121 | + return NF_ACCEPT; | |
122 | + } | |
123 | + } | |
118 | 124 | |
119 | 125 | switch (ctinfo) { |
120 | 126 | case IP_CT_RELATED: |
121 | 127 | |
... | ... | @@ -326,18 +332,10 @@ |
326 | 332 | |
327 | 333 | static int __init nf_nat_standalone_init(void) |
328 | 334 | { |
329 | - int size, ret = 0; | |
335 | + int ret = 0; | |
330 | 336 | |
331 | 337 | need_conntrack(); |
332 | 338 | |
333 | - size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_nat)) + | |
334 | - sizeof(struct nf_conn_nat); | |
335 | - ret = nf_conntrack_register_cache(NF_CT_F_NAT, "nf_nat:base", size); | |
336 | - if (ret < 0) { | |
337 | - printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); | |
338 | - return ret; | |
339 | - } | |
340 | - | |
341 | 339 | #ifdef CONFIG_XFRM |
342 | 340 | BUG_ON(ip_nat_decode_session != NULL); |
343 | 341 | ip_nat_decode_session = nat_decode_session; |
... | ... | @@ -362,7 +360,6 @@ |
362 | 360 | ip_nat_decode_session = NULL; |
363 | 361 | synchronize_net(); |
364 | 362 | #endif |
365 | - nf_conntrack_unregister_cache(NF_CT_F_NAT); | |
366 | 363 | return ret; |
367 | 364 | } |
368 | 365 |