diff options
author | Yasuyuki Kozakai <yasuyuki.kozakai@toshiba.co.jp> | 2007-07-08 01:23:42 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-07-11 01:17:18 -0400 |
commit | ceceae1b1555a9afcb8dacf90df5fa1f20fd5466 (patch) | |
tree | 008841923a297be92566c8da42f516ffe6c2cdc1 /net | |
parent | ecfab2c9fe5597221c2b30dec48634a2361a0d08 (diff) |
[NETFILTER]: nf_conntrack: use extension infrastructure for helper
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/netfilter/nf_nat_standalone.c | 10 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 80 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_helper.c | 27 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_netlink.c | 37 |
4 files changed, 88 insertions, 66 deletions
diff --git a/net/ipv4/netfilter/nf_nat_standalone.c b/net/ipv4/netfilter/nf_nat_standalone.c index 55dac36dbc85..0b2f0c33f7cd 100644 --- a/net/ipv4/netfilter/nf_nat_standalone.c +++ b/net/ipv4/netfilter/nf_nat_standalone.c | |||
@@ -338,14 +338,6 @@ static int __init nf_nat_standalone_init(void) | |||
338 | return ret; | 338 | return ret; |
339 | } | 339 | } |
340 | 340 | ||
341 | size = ALIGN(size, __alignof__(struct nf_conn_help)) + | ||
342 | sizeof(struct nf_conn_help); | ||
343 | ret = nf_conntrack_register_cache(NF_CT_F_NAT|NF_CT_F_HELP, | ||
344 | "nf_nat:help", size); | ||
345 | if (ret < 0) { | ||
346 | printk(KERN_ERR "nf_nat_init: Unable to create slab cache\n"); | ||
347 | goto cleanup_register_cache; | ||
348 | } | ||
349 | #ifdef CONFIG_XFRM | 341 | #ifdef CONFIG_XFRM |
350 | BUG_ON(ip_nat_decode_session != NULL); | 342 | BUG_ON(ip_nat_decode_session != NULL); |
351 | ip_nat_decode_session = nat_decode_session; | 343 | ip_nat_decode_session = nat_decode_session; |
@@ -370,8 +362,6 @@ static int __init nf_nat_standalone_init(void) | |||
370 | ip_nat_decode_session = NULL; | 362 | ip_nat_decode_session = NULL; |
371 | synchronize_net(); | 363 | synchronize_net(); |
372 | #endif | 364 | #endif |
373 | nf_conntrack_unregister_cache(NF_CT_F_NAT|NF_CT_F_HELP); | ||
374 | cleanup_register_cache: | ||
375 | nf_conntrack_unregister_cache(NF_CT_F_NAT); | 365 | nf_conntrack_unregister_cache(NF_CT_F_NAT); |
376 | return ret; | 366 | return ret; |
377 | } | 367 | } |
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index b56f954895bb..914506e6c787 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c | |||
@@ -566,7 +566,6 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
566 | u_int32_t features) | 566 | u_int32_t features) |
567 | { | 567 | { |
568 | struct nf_conn *conntrack = NULL; | 568 | struct nf_conn *conntrack = NULL; |
569 | struct nf_conntrack_helper *helper; | ||
570 | 569 | ||
571 | if (unlikely(!nf_conntrack_hash_rnd_initted)) { | 570 | if (unlikely(!nf_conntrack_hash_rnd_initted)) { |
572 | get_random_bytes(&nf_conntrack_hash_rnd, 4); | 571 | get_random_bytes(&nf_conntrack_hash_rnd, 4); |
@@ -593,14 +592,6 @@ __nf_conntrack_alloc(const struct nf_conntrack_tuple *orig, | |||
593 | /* find features needed by this conntrack. */ | 592 | /* find features needed by this conntrack. */ |
594 | features |= l3proto->get_features(orig); | 593 | features |= l3proto->get_features(orig); |
595 | 594 | ||
596 | /* FIXME: protect helper list per RCU */ | ||
597 | read_lock_bh(&nf_conntrack_lock); | ||
598 | helper = __nf_ct_helper_find(repl); | ||
599 | /* NAT might want to assign a helper later */ | ||
600 | if (helper || features & NF_CT_F_NAT) | ||
601 | features |= NF_CT_F_HELP; | ||
602 | read_unlock_bh(&nf_conntrack_lock); | ||
603 | |||
604 | DEBUGP("nf_conntrack_alloc: features=0x%x\n", features); | 595 | DEBUGP("nf_conntrack_alloc: features=0x%x\n", features); |
605 | 596 | ||
606 | read_lock_bh(&nf_ct_cache_lock); | 597 | read_lock_bh(&nf_ct_cache_lock); |
@@ -681,12 +672,6 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
681 | return NULL; | 672 | return NULL; |
682 | } | 673 | } |
683 | 674 | ||
684 | read_lock_bh(&nf_conntrack_lock); | ||
685 | exp = __nf_conntrack_expect_find(tuple); | ||
686 | if (exp && exp->helper) | ||
687 | features = NF_CT_F_HELP; | ||
688 | read_unlock_bh(&nf_conntrack_lock); | ||
689 | |||
690 | conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto, features); | 675 | conntrack = __nf_conntrack_alloc(tuple, &repl_tuple, l3proto, features); |
691 | if (conntrack == NULL || IS_ERR(conntrack)) { | 676 | if (conntrack == NULL || IS_ERR(conntrack)) { |
692 | DEBUGP("Can't allocate conntrack.\n"); | 677 | DEBUGP("Can't allocate conntrack.\n"); |
@@ -701,16 +686,21 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
701 | 686 | ||
702 | write_lock_bh(&nf_conntrack_lock); | 687 | write_lock_bh(&nf_conntrack_lock); |
703 | exp = find_expectation(tuple); | 688 | exp = find_expectation(tuple); |
704 | |||
705 | help = nfct_help(conntrack); | ||
706 | if (exp) { | 689 | if (exp) { |
707 | DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", | 690 | DEBUGP("conntrack: expectation arrives ct=%p exp=%p\n", |
708 | conntrack, exp); | 691 | conntrack, exp); |
709 | /* Welcome, Mr. Bond. We've been expecting you... */ | 692 | /* Welcome, Mr. Bond. We've been expecting you... */ |
710 | __set_bit(IPS_EXPECTED_BIT, &conntrack->status); | 693 | __set_bit(IPS_EXPECTED_BIT, &conntrack->status); |
711 | conntrack->master = exp->master; | 694 | conntrack->master = exp->master; |
712 | if (exp->helper) | 695 | if (exp->helper) { |
713 | rcu_assign_pointer(help->helper, exp->helper); | 696 | help = nf_ct_ext_add(conntrack, NF_CT_EXT_HELPER, |
697 | GFP_ATOMIC); | ||
698 | if (help) | ||
699 | rcu_assign_pointer(help->helper, exp->helper); | ||
700 | else | ||
701 | DEBUGP("failed to add helper extension area"); | ||
702 | } | ||
703 | |||
714 | #ifdef CONFIG_NF_CONNTRACK_MARK | 704 | #ifdef CONFIG_NF_CONNTRACK_MARK |
715 | conntrack->mark = exp->master->mark; | 705 | conntrack->mark = exp->master->mark; |
716 | #endif | 706 | #endif |
@@ -720,10 +710,18 @@ init_conntrack(const struct nf_conntrack_tuple *tuple, | |||
720 | nf_conntrack_get(&conntrack->master->ct_general); | 710 | nf_conntrack_get(&conntrack->master->ct_general); |
721 | NF_CT_STAT_INC(expect_new); | 711 | NF_CT_STAT_INC(expect_new); |
722 | } else { | 712 | } else { |
723 | if (help) { | 713 | struct nf_conntrack_helper *helper; |
724 | /* not in hash table yet, so not strictly necessary */ | 714 | |
725 | rcu_assign_pointer(help->helper, | 715 | helper = __nf_ct_helper_find(&repl_tuple); |
726 | __nf_ct_helper_find(&repl_tuple)); | 716 | if (helper) { |
717 | help = nf_ct_ext_add(conntrack, NF_CT_EXT_HELPER, | ||
718 | GFP_ATOMIC); | ||
719 | if (help) | ||
720 | /* not in hash table yet, so not strictly | ||
721 | necessary */ | ||
722 | rcu_assign_pointer(help->helper, helper); | ||
723 | else | ||
724 | DEBUGP("failed to add helper extension area"); | ||
727 | } | 725 | } |
728 | NF_CT_STAT_INC(new); | 726 | NF_CT_STAT_INC(new); |
729 | } | 727 | } |
@@ -892,6 +890,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, | |||
892 | const struct nf_conntrack_tuple *newreply) | 890 | const struct nf_conntrack_tuple *newreply) |
893 | { | 891 | { |
894 | struct nf_conn_help *help = nfct_help(ct); | 892 | struct nf_conn_help *help = nfct_help(ct); |
893 | struct nf_conntrack_helper *helper; | ||
895 | 894 | ||
896 | write_lock_bh(&nf_conntrack_lock); | 895 | write_lock_bh(&nf_conntrack_lock); |
897 | /* Should be unconfirmed, so not in hash table yet */ | 896 | /* Should be unconfirmed, so not in hash table yet */ |
@@ -901,14 +900,28 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, | |||
901 | NF_CT_DUMP_TUPLE(newreply); | 900 | NF_CT_DUMP_TUPLE(newreply); |
902 | 901 | ||
903 | ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; | 902 | ct->tuplehash[IP_CT_DIR_REPLY].tuple = *newreply; |
904 | if (!ct->master && help && help->expecting == 0) { | 903 | if (ct->master || (help && help->expecting != 0)) |
905 | struct nf_conntrack_helper *helper; | 904 | goto out; |
906 | helper = __nf_ct_helper_find(newreply); | 905 | |
907 | if (helper) | 906 | helper = __nf_ct_helper_find(newreply); |
908 | memset(&help->help, 0, sizeof(help->help)); | 907 | if (helper == NULL) { |
909 | /* not in hash table yet, so not strictly necessary */ | 908 | if (help) |
910 | rcu_assign_pointer(help->helper, helper); | 909 | rcu_assign_pointer(help->helper, NULL); |
910 | goto out; | ||
911 | } | 911 | } |
912 | |||
913 | if (help == NULL) { | ||
914 | help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_ATOMIC); | ||
915 | if (help == NULL) { | ||
916 | DEBUGP("failed to add helper extension area"); | ||
917 | goto out; | ||
918 | } | ||
919 | } else { | ||
920 | memset(&help->help, 0, sizeof(help->help)); | ||
921 | } | ||
922 | |||
923 | rcu_assign_pointer(help->helper, helper); | ||
924 | out: | ||
912 | write_unlock_bh(&nf_conntrack_lock); | 925 | write_unlock_bh(&nf_conntrack_lock); |
913 | } | 926 | } |
914 | EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); | 927 | EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); |
@@ -1150,6 +1163,7 @@ void nf_conntrack_cleanup(void) | |||
1150 | nf_conntrack_htable_size); | 1163 | nf_conntrack_htable_size); |
1151 | 1164 | ||
1152 | nf_conntrack_proto_fini(); | 1165 | nf_conntrack_proto_fini(); |
1166 | nf_conntrack_helper_fini(); | ||
1153 | } | 1167 | } |
1154 | 1168 | ||
1155 | static struct list_head *alloc_hashtable(int size, int *vmalloced) | 1169 | static struct list_head *alloc_hashtable(int size, int *vmalloced) |
@@ -1272,6 +1286,10 @@ int __init nf_conntrack_init(void) | |||
1272 | if (ret < 0) | 1286 | if (ret < 0) |
1273 | goto out_free_expect_slab; | 1287 | goto out_free_expect_slab; |
1274 | 1288 | ||
1289 | ret = nf_conntrack_helper_init(); | ||
1290 | if (ret < 0) | ||
1291 | goto out_fini_proto; | ||
1292 | |||
1275 | /* For use by REJECT target */ | 1293 | /* For use by REJECT target */ |
1276 | rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach); | 1294 | rcu_assign_pointer(ip_ct_attach, __nf_conntrack_attach); |
1277 | rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); | 1295 | rcu_assign_pointer(nf_ct_destroy, destroy_conntrack); |
@@ -1284,6 +1302,8 @@ int __init nf_conntrack_init(void) | |||
1284 | 1302 | ||
1285 | return ret; | 1303 | return ret; |
1286 | 1304 | ||
1305 | out_fini_proto: | ||
1306 | nf_conntrack_proto_fini(); | ||
1287 | out_free_expect_slab: | 1307 | out_free_expect_slab: |
1288 | kmem_cache_destroy(nf_conntrack_expect_cachep); | 1308 | kmem_cache_destroy(nf_conntrack_expect_cachep); |
1289 | err_free_conntrack_slab: | 1309 | err_free_conntrack_slab: |
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index f868b7fbd9b4..6d32399d64e1 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <net/netfilter/nf_conntrack_l4proto.h> | 26 | #include <net/netfilter/nf_conntrack_l4proto.h> |
27 | #include <net/netfilter/nf_conntrack_helper.h> | 27 | #include <net/netfilter/nf_conntrack_helper.h> |
28 | #include <net/netfilter/nf_conntrack_core.h> | 28 | #include <net/netfilter/nf_conntrack_core.h> |
29 | #include <net/netfilter/nf_conntrack_extend.h> | ||
29 | 30 | ||
30 | static __read_mostly LIST_HEAD(helpers); | 31 | static __read_mostly LIST_HEAD(helpers); |
31 | 32 | ||
@@ -100,18 +101,8 @@ static inline int unhelp(struct nf_conntrack_tuple_hash *i, | |||
100 | 101 | ||
101 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) | 102 | int nf_conntrack_helper_register(struct nf_conntrack_helper *me) |
102 | { | 103 | { |
103 | int size, ret; | ||
104 | |||
105 | BUG_ON(me->timeout == 0); | 104 | BUG_ON(me->timeout == 0); |
106 | 105 | ||
107 | size = ALIGN(sizeof(struct nf_conn), __alignof__(struct nf_conn_help)) + | ||
108 | sizeof(struct nf_conn_help); | ||
109 | ret = nf_conntrack_register_cache(NF_CT_F_HELP, "nf_conntrack:help", | ||
110 | size); | ||
111 | if (ret < 0) { | ||
112 | printk(KERN_ERR "nf_conntrack_helper_register: Unable to create slab cache for conntracks\n"); | ||
113 | return ret; | ||
114 | } | ||
115 | write_lock_bh(&nf_conntrack_lock); | 106 | write_lock_bh(&nf_conntrack_lock); |
116 | list_add(&me->list, &helpers); | 107 | list_add(&me->list, &helpers); |
117 | write_unlock_bh(&nf_conntrack_lock); | 108 | write_unlock_bh(&nf_conntrack_lock); |
@@ -153,3 +144,19 @@ void nf_conntrack_helper_unregister(struct nf_conntrack_helper *me) | |||
153 | synchronize_net(); | 144 | synchronize_net(); |
154 | } | 145 | } |
155 | EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); | 146 | EXPORT_SYMBOL_GPL(nf_conntrack_helper_unregister); |
147 | |||
148 | struct nf_ct_ext_type helper_extend = { | ||
149 | .len = sizeof(struct nf_conn_help), | ||
150 | .align = __alignof__(struct nf_conn_help), | ||
151 | .id = NF_CT_EXT_HELPER, | ||
152 | }; | ||
153 | |||
154 | int nf_conntrack_helper_init() | ||
155 | { | ||
156 | return nf_ct_extend_register(&helper_extend); | ||
157 | } | ||
158 | |||
159 | void nf_conntrack_helper_fini() | ||
160 | { | ||
161 | nf_ct_extend_unregister(&helper_extend); | ||
162 | } | ||
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index d0fe3d769828..3d56f36074f7 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c | |||
@@ -856,23 +856,23 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[]) | |||
856 | return 0; | 856 | return 0; |
857 | } | 857 | } |
858 | 858 | ||
859 | if (!help) { | ||
860 | /* FIXME: we need to reallocate and rehash */ | ||
861 | return -EBUSY; | ||
862 | } | ||
863 | |||
864 | helper = __nf_conntrack_helper_find_byname(helpname); | 859 | helper = __nf_conntrack_helper_find_byname(helpname); |
865 | if (helper == NULL) | 860 | if (helper == NULL) |
866 | return -EINVAL; | 861 | return -EINVAL; |
867 | 862 | ||
868 | if (help->helper == helper) | 863 | if (help) { |
869 | return 0; | 864 | if (help->helper == helper) |
870 | 865 | return 0; | |
871 | if (help->helper) | 866 | if (help->helper) |
872 | return -EBUSY; | 867 | return -EBUSY; |
868 | /* need to zero data of old helper */ | ||
869 | memset(&help->help, 0, sizeof(help->help)); | ||
870 | } else { | ||
871 | help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_KERNEL); | ||
872 | if (help == NULL) | ||
873 | return -ENOMEM; | ||
874 | } | ||
873 | 875 | ||
874 | /* need to zero data of old helper */ | ||
875 | memset(&help->help, 0, sizeof(help->help)); | ||
876 | rcu_assign_pointer(help->helper, helper); | 876 | rcu_assign_pointer(help->helper, helper); |
877 | 877 | ||
878 | return 0; | 878 | return 0; |
@@ -957,7 +957,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
957 | struct nf_conn *ct; | 957 | struct nf_conn *ct; |
958 | int err = -EINVAL; | 958 | int err = -EINVAL; |
959 | struct nf_conn_help *help; | 959 | struct nf_conn_help *help; |
960 | struct nf_conntrack_helper *helper = NULL; | 960 | struct nf_conntrack_helper *helper; |
961 | 961 | ||
962 | ct = nf_conntrack_alloc(otuple, rtuple); | 962 | ct = nf_conntrack_alloc(otuple, rtuple); |
963 | if (ct == NULL || IS_ERR(ct)) | 963 | if (ct == NULL || IS_ERR(ct)) |
@@ -987,9 +987,14 @@ ctnetlink_create_conntrack(struct nfattr *cda[], | |||
987 | ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); | 987 | ct->mark = ntohl(*(__be32 *)NFA_DATA(cda[CTA_MARK-1])); |
988 | #endif | 988 | #endif |
989 | 989 | ||
990 | help = nfct_help(ct); | 990 | helper = nf_ct_helper_find_get(rtuple); |
991 | if (help) { | 991 | if (helper) { |
992 | helper = nf_ct_helper_find_get(rtuple); | 992 | help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_KERNEL); |
993 | if (help == NULL) { | ||
994 | nf_ct_helper_put(helper); | ||
995 | err = -ENOMEM; | ||
996 | goto err; | ||
997 | } | ||
993 | /* not in hash table yet so not strictly necessary */ | 998 | /* not in hash table yet so not strictly necessary */ |
994 | rcu_assign_pointer(help->helper, helper); | 999 | rcu_assign_pointer(help->helper, helper); |
995 | } | 1000 | } |