aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2007-07-08 01:35:56 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-07-11 01:18:02 -0400
commitb560580a13b180bc1e3cad7ffbc93388cc39be5d (patch)
tree9ad6fd7a93c75ef4776239b4f43bde27737aa04b
parent31f15875c5ad98a13b528aaf19c839e22b43dc9a (diff)
[NETFILTER]: nf_conntrack_expect: maintain per conntrack expectation list
This patch brings back the per-conntrack expectation list that was removed around 2.6.10 to avoid walking all expectations on expectation eviction and conntrack destruction. As these were the last users of the global expectation list, this patch also kills that. Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/net/netfilter/nf_conntrack.h2
-rw-r--r--include/net/netfilter/nf_conntrack_expect.h5
-rw-r--r--include/net/netfilter/nf_conntrack_helper.h2
-rw-r--r--net/netfilter/nf_conntrack_core.c18
-rw-r--r--net/netfilter/nf_conntrack_expect.c40
-rw-r--r--net/netfilter/nf_conntrack_helper.c13
-rw-r--r--net/netfilter/nf_conntrack_netlink.c4
7 files changed, 45 insertions, 39 deletions
diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index 8f2cbb965f3d..d4f02eb0c66c 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -82,6 +82,8 @@ struct nf_conn_help {
82 82
83 union nf_conntrack_help help; 83 union nf_conntrack_help help;
84 84
85 struct hlist_head expectations;
86
85 /* Current number of expected connections */ 87 /* Current number of expected connections */
86 unsigned int expecting; 88 unsigned int expecting;
87}; 89};
diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h
index 424d4bdb9848..9d5af4e22c4f 100644
--- a/include/net/netfilter/nf_conntrack_expect.h
+++ b/include/net/netfilter/nf_conntrack_expect.h
@@ -6,14 +6,13 @@
6#define _NF_CONNTRACK_EXPECT_H 6#define _NF_CONNTRACK_EXPECT_H
7#include <net/netfilter/nf_conntrack.h> 7#include <net/netfilter/nf_conntrack.h>
8 8
9extern struct list_head nf_ct_expect_list;
10extern struct hlist_head *nf_ct_expect_hash; 9extern struct hlist_head *nf_ct_expect_hash;
11extern unsigned int nf_ct_expect_hsize; 10extern unsigned int nf_ct_expect_hsize;
12 11
13struct nf_conntrack_expect 12struct nf_conntrack_expect
14{ 13{
15 /* Internal linked list (global expectation list) */ 14 /* Conntrack expectation list member */
16 struct list_head list; 15 struct hlist_node lnode;
17 16
18 /* Hash member */ 17 /* Hash member */
19 struct hlist_node hnode; 18 struct hlist_node hnode;
diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h
index d62e6f093af4..2c0e2e0fb7ff 100644
--- a/include/net/netfilter/nf_conntrack_helper.h
+++ b/include/net/netfilter/nf_conntrack_helper.h
@@ -52,6 +52,8 @@ extern void nf_ct_helper_put(struct nf_conntrack_helper *helper);
52extern int nf_conntrack_helper_register(struct nf_conntrack_helper *); 52extern int nf_conntrack_helper_register(struct nf_conntrack_helper *);
53extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); 53extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *);
54 54
55extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp);
56
55static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) 57static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct)
56{ 58{
57 return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); 59 return nf_ct_ext_find(ct, NF_CT_EXT_HELPER);
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c
index ed44a09ae739..d1fc019760a1 100644
--- a/net/netfilter/nf_conntrack_core.c
+++ b/net/netfilter/nf_conntrack_core.c
@@ -502,12 +502,9 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
502 __set_bit(IPS_EXPECTED_BIT, &conntrack->status); 502 __set_bit(IPS_EXPECTED_BIT, &conntrack->status);
503 conntrack->master = exp->master; 503 conntrack->master = exp->master;
504 if (exp->helper) { 504 if (exp->helper) {
505 help = nf_ct_ext_add(conntrack, NF_CT_EXT_HELPER, 505 help = nf_ct_helper_ext_add(conntrack, GFP_ATOMIC);
506 GFP_ATOMIC);
507 if (help) 506 if (help)
508 rcu_assign_pointer(help->helper, exp->helper); 507 rcu_assign_pointer(help->helper, exp->helper);
509 else
510 DEBUGP("failed to add helper extension area");
511 } 508 }
512 509
513#ifdef CONFIG_NF_CONNTRACK_MARK 510#ifdef CONFIG_NF_CONNTRACK_MARK
@@ -523,14 +520,9 @@ init_conntrack(const struct nf_conntrack_tuple *tuple,
523 520
524 helper = __nf_ct_helper_find(&repl_tuple); 521 helper = __nf_ct_helper_find(&repl_tuple);
525 if (helper) { 522 if (helper) {
526 help = nf_ct_ext_add(conntrack, NF_CT_EXT_HELPER, 523 help = nf_ct_helper_ext_add(conntrack, GFP_ATOMIC);
527 GFP_ATOMIC);
528 if (help) 524 if (help)
529 /* not in hash table yet, so not strictly
530 necessary */
531 rcu_assign_pointer(help->helper, helper); 525 rcu_assign_pointer(help->helper, helper);
532 else
533 DEBUGP("failed to add helper extension area");
534 } 526 }
535 NF_CT_STAT_INC(new); 527 NF_CT_STAT_INC(new);
536 } 528 }
@@ -721,11 +713,9 @@ void nf_conntrack_alter_reply(struct nf_conn *ct,
721 } 713 }
722 714
723 if (help == NULL) { 715 if (help == NULL) {
724 help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_ATOMIC); 716 help = nf_ct_helper_ext_add(ct, GFP_ATOMIC);
725 if (help == NULL) { 717 if (help == NULL)
726 DEBUGP("failed to add helper extension area");
727 goto out; 718 goto out;
728 }
729 } else { 719 } else {
730 memset(&help->help, 0, sizeof(help->help)); 720 memset(&help->help, 0, sizeof(help->help));
731 } 721 }
diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c
index c5006b0a4e65..5ef0dd439e76 100644
--- a/net/netfilter/nf_conntrack_expect.c
+++ b/net/netfilter/nf_conntrack_expect.c
@@ -27,9 +27,6 @@
27#include <net/netfilter/nf_conntrack_helper.h> 27#include <net/netfilter/nf_conntrack_helper.h>
28#include <net/netfilter/nf_conntrack_tuple.h> 28#include <net/netfilter/nf_conntrack_tuple.h>
29 29
30LIST_HEAD(nf_ct_expect_list);
31EXPORT_SYMBOL_GPL(nf_ct_expect_list);
32
33struct hlist_head *nf_ct_expect_hash __read_mostly; 30struct hlist_head *nf_ct_expect_hash __read_mostly;
34EXPORT_SYMBOL_GPL(nf_ct_expect_hash); 31EXPORT_SYMBOL_GPL(nf_ct_expect_hash);
35 32
@@ -52,13 +49,14 @@ void nf_ct_unlink_expect(struct nf_conntrack_expect *exp)
52 NF_CT_ASSERT(master_help); 49 NF_CT_ASSERT(master_help);
53 NF_CT_ASSERT(!timer_pending(&exp->timeout)); 50 NF_CT_ASSERT(!timer_pending(&exp->timeout));
54 51
55 list_del(&exp->list);
56 hlist_del(&exp->hnode); 52 hlist_del(&exp->hnode);
57 nf_ct_expect_count--; 53 nf_ct_expect_count--;
58 54
59 NF_CT_STAT_INC(expect_delete); 55 hlist_del(&exp->lnode);
60 master_help->expecting--; 56 master_help->expecting--;
61 nf_ct_expect_put(exp); 57 nf_ct_expect_put(exp);
58
59 NF_CT_STAT_INC(expect_delete);
62} 60}
63EXPORT_SYMBOL_GPL(nf_ct_unlink_expect); 61EXPORT_SYMBOL_GPL(nf_ct_unlink_expect);
64 62
@@ -153,17 +151,18 @@ nf_ct_find_expectation(const struct nf_conntrack_tuple *tuple)
153/* delete all expectations for this conntrack */ 151/* delete all expectations for this conntrack */
154void nf_ct_remove_expectations(struct nf_conn *ct) 152void nf_ct_remove_expectations(struct nf_conn *ct)
155{ 153{
156 struct nf_conntrack_expect *i, *tmp;
157 struct nf_conn_help *help = nfct_help(ct); 154 struct nf_conn_help *help = nfct_help(ct);
155 struct nf_conntrack_expect *exp;
156 struct hlist_node *n, *next;
158 157
159 /* Optimization: most connection never expect any others. */ 158 /* Optimization: most connection never expect any others. */
160 if (!help || help->expecting == 0) 159 if (!help || help->expecting == 0)
161 return; 160 return;
162 161
163 list_for_each_entry_safe(i, tmp, &nf_ct_expect_list, list) { 162 hlist_for_each_entry_safe(exp, n, next, &help->expectations, lnode) {
164 if (i->master == ct && del_timer(&i->timeout)) { 163 if (del_timer(&exp->timeout)) {
165 nf_ct_unlink_expect(i); 164 nf_ct_unlink_expect(exp);
166 nf_ct_expect_put(i); 165 nf_ct_expect_put(exp);
167 } 166 }
168 } 167 }
169} 168}
@@ -289,9 +288,10 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
289 unsigned int h = nf_ct_expect_dst_hash(&exp->tuple); 288 unsigned int h = nf_ct_expect_dst_hash(&exp->tuple);
290 289
291 atomic_inc(&exp->use); 290 atomic_inc(&exp->use);
291
292 hlist_add_head(&exp->lnode, &master_help->expectations);
292 master_help->expecting++; 293 master_help->expecting++;
293 294
294 list_add(&exp->list, &nf_ct_expect_list);
295 hlist_add_head(&exp->hnode, &nf_ct_expect_hash[h]); 295 hlist_add_head(&exp->hnode, &nf_ct_expect_hash[h]);
296 nf_ct_expect_count++; 296 nf_ct_expect_count++;
297 297
@@ -308,16 +308,16 @@ static void nf_ct_expect_insert(struct nf_conntrack_expect *exp)
308/* Race with expectations being used means we could have none to find; OK. */ 308/* Race with expectations being used means we could have none to find; OK. */
309static void evict_oldest_expect(struct nf_conn *master) 309static void evict_oldest_expect(struct nf_conn *master)
310{ 310{
311 struct nf_conntrack_expect *i; 311 struct nf_conn_help *master_help = nfct_help(master);
312 struct nf_conntrack_expect *exp = NULL;
313 struct hlist_node *n;
312 314
313 list_for_each_entry_reverse(i, &nf_ct_expect_list, list) { 315 hlist_for_each_entry(exp, n, &master_help->expectations, lnode)
314 if (i->master == master) { 316 ; /* nothing */
315 if (del_timer(&i->timeout)) { 317
316 nf_ct_unlink_expect(i); 318 if (exp && del_timer(&exp->timeout)) {
317 nf_ct_expect_put(i); 319 nf_ct_unlink_expect(exp);
318 } 320 nf_ct_expect_put(exp);
319 break;
320 }
321 } 321 }
322} 322}
323 323
diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c
index cc8ae7404ac4..66c209d7e09d 100644
--- a/net/netfilter/nf_conntrack_helper.c
+++ b/net/netfilter/nf_conntrack_helper.c
@@ -87,6 +87,19 @@ __nf_conntrack_helper_find_byname(const char *name)
87} 87}
88EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname); 88EXPORT_SYMBOL_GPL(__nf_conntrack_helper_find_byname);
89 89
90struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp)
91{
92 struct nf_conn_help *help;
93
94 help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, gfp);
95 if (help)
96 INIT_HLIST_HEAD(&help->expectations);
97 else
98 pr_debug("failed to add helper extension area");
99 return help;
100}
101EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add);
102
90static inline int unhelp(struct nf_conntrack_tuple_hash *i, 103static inline int unhelp(struct nf_conntrack_tuple_hash *i,
91 const struct nf_conntrack_helper *me) 104 const struct nf_conntrack_helper *me)
92{ 105{
diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c
index 60af9b6b9e00..6f89b105a205 100644
--- a/net/netfilter/nf_conntrack_netlink.c
+++ b/net/netfilter/nf_conntrack_netlink.c
@@ -868,7 +868,7 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nfattr *cda[])
868 /* need to zero data of old helper */ 868 /* need to zero data of old helper */
869 memset(&help->help, 0, sizeof(help->help)); 869 memset(&help->help, 0, sizeof(help->help));
870 } else { 870 } else {
871 help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_KERNEL); 871 help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
872 if (help == NULL) 872 if (help == NULL)
873 return -ENOMEM; 873 return -ENOMEM;
874 } 874 }
@@ -989,7 +989,7 @@ ctnetlink_create_conntrack(struct nfattr *cda[],
989 989
990 helper = nf_ct_helper_find_get(rtuple); 990 helper = nf_ct_helper_find_get(rtuple);
991 if (helper) { 991 if (helper) {
992 help = nf_ct_ext_add(ct, NF_CT_EXT_HELPER, GFP_KERNEL); 992 help = nf_ct_helper_ext_add(ct, GFP_KERNEL);
993 if (help == NULL) { 993 if (help == NULL) {
994 nf_ct_helper_put(helper); 994 nf_ct_helper_put(helper);
995 err = -ENOMEM; 995 err = -ENOMEM;