diff options
author | Martin Josefsson <gandalf@wlug.westbo.se> | 2006-11-29 02:34:58 +0100 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2006-12-02 21:31:04 -0800 |
commit | 77ab9cff0f4112703df3ef7903c1a15adb967114 (patch) | |
tree | 6361b73598e237398d959afdd158c70b68354b09 /net/netfilter/nf_conntrack_core.c | |
parent | d2e4bdc8704b0e711c5046a430bfd1681b0bd5a9 (diff) |
[NETFILTER]: nf_conntrack: split out expectation handling
This patch splits out expectation handling into its own file
nf_conntrack_expect.c
Signed-off-by: Martin Josefsson <gandalf@wlug.westbo.se>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Diffstat (limited to 'net/netfilter/nf_conntrack_core.c')
-rw-r--r-- | net/netfilter/nf_conntrack_core.c | 265 |
1 files changed, 2 insertions, 263 deletions
diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index de0567b1f42..72fbae4e594 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -55,6 +55,7 @@ #include <net/netfilter/nf_conntrack.h> #include <net/netfilter/nf_conntrack_l3proto.h> #include <net/netfilter/nf_conntrack_protocol.h> +#include <net/netfilter/nf_conntrack_expect.h> #include <net/netfilter/nf_conntrack_helper.h> #include <net/netfilter/nf_conntrack_core.h> @@ -72,21 +73,19 @@ DEFINE_RWLOCK(nf_conntrack_lock); atomic_t nf_conntrack_count = ATOMIC_INIT(0); void (*nf_conntrack_destroyed)(struct nf_conn *conntrack) = NULL; -LIST_HEAD(nf_conntrack_expect_list); struct nf_conntrack_protocol **nf_ct_protos[PF_MAX] __read_mostly; struct nf_conntrack_l3proto *nf_ct_l3protos[PF_MAX] __read_mostly; static LIST_HEAD(helpers); unsigned int nf_conntrack_htable_size __read_mostly = 0; int nf_conntrack_max __read_mostly; struct list_head *nf_conntrack_hash __read_mostly; -static kmem_cache_t *nf_conntrack_expect_cachep __read_mostly; struct nf_conn nf_conntrack_untracked; unsigned int nf_ct_log_invalid __read_mostly; static LIST_HEAD(unconfirmed); static int nf_conntrack_vmalloc __read_mostly; static unsigned int nf_conntrack_next_id; -static unsigned int nf_conntrack_expect_next_id; + #ifdef CONFIG_NF_CONNTRACK_EVENTS ATOMIC_NOTIFIER_HEAD(nf_conntrack_chain); ATOMIC_NOTIFIER_HEAD(nf_conntrack_expect_chain); @@ -438,103 +437,6 @@ nf_ct_invert_tuple(struct nf_conntrack_tuple *inverse, return protocol->invert_tuple(inverse, orig); } -/* nf_conntrack_expect helper functions */ -void nf_ct_unlink_expect(struct nf_conntrack_expect *exp) -{ - struct nf_conn_help *master_help = nfct_help(exp->master); - - NF_CT_ASSERT(master_help); - ASSERT_WRITE_LOCK(&nf_conntrack_lock); - NF_CT_ASSERT(!timer_pending(&exp->timeout)); - - list_del(&exp->list); - NF_CT_STAT_INC(expect_delete); - master_help->expecting--; - nf_conntrack_expect_put(exp); -} - -static void expectation_timed_out(unsigned long ul_expect) -{ - struct nf_conntrack_expect *exp = (void *)ul_expect; - - write_lock_bh(&nf_conntrack_lock); - nf_ct_unlink_expect(exp); - write_unlock_bh(&nf_conntrack_lock); - nf_conntrack_expect_put(exp); -} - -struct nf_conntrack_expect * -__nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple) -{ - struct nf_conntrack_expect *i; - - list_for_each_entry(i, &nf_conntrack_expect_list, list) { - if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask)) - return i; - } - return NULL; -} - -/* Just find a expectation corresponding to a tuple. */ -struct nf_conntrack_expect * -nf_conntrack_expect_find(const struct nf_conntrack_tuple *tuple) -{ - struct nf_conntrack_expect *i; - - read_lock_bh(&nf_conntrack_lock); - i = __nf_conntrack_expect_find(tuple); - if (i) - atomic_inc(&i->use); - read_unlock_bh(&nf_conntrack_lock); - - return i; -} - -/* If an expectation for this connection is found, it gets delete from - * global list then returned. */ -static struct nf_conntrack_expect * -find_expectation(const struct nf_conntrack_tuple *tuple) -{ - struct nf_conntrack_expect *i; - - list_for_each_entry(i, &nf_conntrack_expect_list, list) { - /* If master is not in hash table yet (ie. packet hasn't left - this machine yet), how can other end know about expected? - Hence these are not the droids you are looking for (if - master ct never got confirmed, we'd hold a reference to it - and weird things would happen to future packets). */ - if (nf_ct_tuple_mask_cmp(tuple, &i->tuple, &i->mask) - && nf_ct_is_confirmed(i->master)) { - if (i->flags & NF_CT_EXPECT_PERMANENT) { - atomic_inc(&i->use); - return i; - } else if (del_timer(&i->timeout)) { - nf_ct_unlink_expect(i); - return i; - } - } - } - return NULL; -} - -/* delete all expectations for this conntrack */ -void nf_ct_remove_expectations(struct nf_conn *ct) -{ - struct nf_conntrack_expect *i, *tmp; - struct nf_conn_help *help = nfct_help(ct); - - /* Optimization: most connection never expect any others. */ - if (!help || help->expecting == 0) - return; - - list_for_each_entry_safe(i, tmp, &nf_conntrack_expect_list, list) { - if (i->master == ct && del_timer(&i->timeout)) { - nf_ct_unlink_expect(i); - nf_conntrack_expect_put(i); - } - } -} - static void clean_from_lists(struct nf_conn *ct) { @@ -1133,169 +1035,6 @@ int nf_ct_invert_tuplepr(struct nf_conntrack_tuple *inverse, orig->dst.protonum)); } -/* Would two expected things clash? */ -static inline int expect_clash(const struct nf_conntrack_expect *a, - const struct nf_conntrack_expect *b) -{ - /* Part covered by intersection of masks must be unequal, - otherwise they clash */ - struct nf_conntrack_tuple intersect_mask; - int count; - - intersect_mask.src.l3num = a->mask.src.l3num & b->mask.src.l3num; - intersect_mask.src.u.all = a->mask.src.u.all & b->mask.src.u.all; - intersect_mask.dst.u.all = a->mask.dst.u.all & b->mask.dst.u.all; - intersect_mask.dst.protonum = a->mask.dst.protonum - & b->mask.dst.protonum; - - for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){ - intersect_mask.src.u3.all[count] = - a->mask.src.u3.all[count] & b->mask.src.u3.all[count]; - } - - for (count = 0; count < NF_CT_TUPLE_L3SIZE; count++){ - intersect_mask.dst.u3.all[count] = - a->mask.dst.u3.all[count] & b->mask.dst.u3.all[count]; - } - - return nf_ct_tuple_mask_cmp(&a->tuple, &b->tuple, &intersect_mask); -} - -static inline int expect_matches(const struct nf_conntrack_expect *a, - const struct nf_conntrack_expect *b) -{ - return a->master == b->master - && nf_ct_tuple_equal(&a->tuple, &b->tuple) - && nf_ct_tuple_equal(&a->mask, &b->mask); -} - -/* Generally a bad idea to call this: could have matched already. */ -void nf_conntrack_unexpect_related(struct nf_conntrack_expect *exp) -{ - struct nf_conntrack_expect *i; - - write_lock_bh(&nf_conntrack_lock); - /* choose the the oldest expectation to evict */ - list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) { - if (expect_matches(i, exp) && del_timer(&i->timeout)) { - nf_ct_unlink_expect(i); - write_unlock_bh(&nf_conntrack_lock); - nf_conntrack_expect_put(i); - return; - } - } - write_unlock_bh(&nf_conntrack_lock); -} - -/* We don't increase the master conntrack refcount for non-fulfilled - * conntracks. During the conntrack destruction, the expectations are - * always killed before the conntrack itself */ -struct nf_conntrack_expect *nf_conntrack_expect_alloc(struct nf_conn *me) -{ - struct nf_conntrack_expect *new; - - new = kmem_cache_alloc(nf_conntrack_expect_cachep, GFP_ATOMIC); - if (!new) { - DEBUGP("expect_related: OOM allocating expect\n"); - return NULL; - } - new->master = me; - atomic_set(&new->use, 1); - return new; -} - -void nf_conntrack_expect_put(struct nf_conntrack_expect *exp) -{ - if (atomic_dec_and_test(&exp->use)) - kmem_cache_free(nf_conntrack_expect_cachep, exp); -} - -static void nf_conntrack_expect_insert(struct nf_conntrack_expect *exp) -{ - struct nf_conn_help *master_help = nfct_help(exp->master); - - atomic_inc(&exp->use); - master_help->expecting++; - list_add(&exp->list, &nf_conntrack_expect_list); - - init_timer(&exp->timeout); - exp->timeout.data = (unsigned long)exp; - exp->timeout.function = expectation_timed_out; - exp->timeout.expires = jiffies + master_help->helper->timeout * HZ; - add_timer(&exp->timeout); - - exp->id = ++nf_conntrack_expect_next_id; - atomic_inc(&exp->use); - NF_CT_STAT_INC(expect_create); -} - -/* Race with expectations being used means we could have none to find; OK. */ -static void evict_oldest_expect(struct nf_conn *master) -{ - struct nf_conntrack_expect *i; - - list_for_each_entry_reverse(i, &nf_conntrack_expect_list, list) { - if (i->master == master) { - if (del_timer(&i->timeout)) { - nf_ct_unlink_expect(i); - nf_conntrack_expect_put(i); - } - break; - } - } -} - -static inline int refresh_timer(struct nf_conntrack_expect *i) -{ - struct nf_conn_help *master_help = nfct_help(i->master); - - if (!del_timer(&i->timeout)) - return 0; - - i->timeout.expires = jiffies + master_help->helper->timeout*HZ; - add_timer(&i->timeout); - return 1; -} - -int nf_conntrack_expect_related(struct nf_conntrack_expect *expect) -{ - struct nf_conntrack_expect *i; - struct nf_conn *master = expect->master; - struct nf_conn_help *master_help = nfct_help(master); - int ret; - - NF_CT_ASSERT(master_help); - - DEBUGP("nf_conntrack_expect_related %p\n", related_to); - DEBUGP("tuple: "); NF_CT_DUMP_TUPLE(&expect->tuple); - DEBUGP("mask: "); NF_CT_DUMP_TUPLE(&expect->mask); - - write_lock_bh(&nf_conntrack_lock); - list_for_each_entry(i, &nf_conntrack_expect_list, list) { - if (expect_matches(i, expect)) { - /* Refresh timer: if it's dying, ignore.. */ - if (refresh_timer(i)) { - ret = 0; - goto out; - } - } else if (expect_clash(i, expect)) { - ret = -EBUSY; - goto out; - } - } - /* Will be over limit? */ - if (master_help->helper->max_expected && - master_help->expecting >= master_help->helper->max_expected) - evict_oldest_expect(master); - - nf_conntrack_expect_insert(expect); - nf_conntrack_expect_event(IPEXP_NEW, expect); - ret = 0; -out: - write_unlock_bh(&nf_conntrack_lock); - return ret; -} - int nf_conntrack_helper_register(struct nf_conntrack_helper *me) { int ret; |