diff -urN linux-2.4.28-pre3-pomng-040917/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.28-pre3-pomng-040917-ctstat/include/linux/netfilter_ipv4/ip_conntrack.h --- linux-2.4.28-pre3-pomng-040917/include/linux/netfilter_ipv4/ip_conntrack.h Fri Sep 17 12:04:36 2004 +++ linux-2.4.28-pre3-pomng-040917-ctstat/include/linux/netfilter_ipv4/ip_conntrack.h Fri Sep 17 12:11:08 2004 @@ -286,5 +286,25 @@ } extern unsigned int ip_conntrack_htable_size; + +struct ip_conntrack_stat +{ + unsigned int searched; + unsigned int found; + unsigned int new; + unsigned int invalid; + unsigned int ignore; + unsigned int delete; + unsigned int delete_list; + unsigned int insert; + unsigned int insert_failed; + unsigned int drop; + unsigned int early_drop; + unsigned int icmp_error; + unsigned int expect_new; + unsigned int expect_create; + unsigned int expect_delete; +} ____cacheline_aligned_in_smp; + #endif /* __KERNEL__ */ #endif /* _IP_CONNTRACK_H */ diff -urN linux-2.4.28-pre3-pomng-040917/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.28-pre3-pomng-040917-ctstat/net/ipv4/netfilter/ip_conntrack_core.c --- linux-2.4.28-pre3-pomng-040917/net/ipv4/netfilter/ip_conntrack_core.c Fri Sep 17 12:04:36 2004 +++ linux-2.4.28-pre3-pomng-040917-ctstat/net/ipv4/netfilter/ip_conntrack_core.c Fri Sep 17 13:12:08 2004 @@ -61,10 +61,12 @@ static LIST_HEAD(helpers); unsigned int ip_conntrack_htable_size = 0; int ip_conntrack_max = 0; -static atomic_t ip_conntrack_count = ATOMIC_INIT(0); +atomic_t ip_conntrack_count = ATOMIC_INIT(0); struct list_head *ip_conntrack_hash; static kmem_cache_t *ip_conntrack_cachep; +struct ip_conntrack_stat ip_conntrack_stat[NR_CPUS]; + extern struct ip_conntrack_protocol ip_conntrack_generic_protocol; static inline int proto_cmpfn(const struct ip_conntrack_protocol *curr, @@ -179,6 +181,7 @@ IP_NF_ASSERT(!timer_pending(&exp->timeout)); kfree(exp); + ip_conntrack_stat[smp_processor_id()].expect_delete++; } inline void ip_conntrack_expect_put(struct ip_conntrack_expect *exp) @@ -347,12 +350,15 @@ DEBUGP("destroy_conntrack: returning ct=%p to slab\n", ct); kmem_cache_free(ip_conntrack_cachep, ct); atomic_dec(&ip_conntrack_count); + ip_conntrack_stat[smp_processor_id()].delete++; } static void death_by_timeout(unsigned long ul_conntrack) { struct ip_conntrack *ct = (void *)ul_conntrack; + ip_conntrack_stat[smp_processor_id()].delete_list++; + WRITE_LOCK(&ip_conntrack_lock); clean_from_lists(ct); WRITE_UNLOCK(&ip_conntrack_lock); @@ -375,13 +381,18 @@ { struct ip_conntrack_tuple_hash *h; unsigned int hash = hash_conntrack(tuple); + unsigned int cpu = smp_processor_id(); MUST_BE_READ_LOCKED(&ip_conntrack_lock); - h = LIST_FIND(&ip_conntrack_hash[hash], - conntrack_tuple_cmp, - struct ip_conntrack_tuple_hash *, - tuple, ignored_conntrack); - return h; + list_for_each_entry(h, &ip_conntrack_hash[hash], list) { + if (conntrack_tuple_cmp(h, tuple, ignored_conntrack)) { + ip_conntrack_stat[cpu].found++; + return h; + } + ip_conntrack_stat[cpu].searched++; + } + + return NULL; } /* Find a connection corresponding to a tuple. */ @@ -475,10 +486,12 @@ atomic_inc(&ct->ct_general.use); set_bit(IPS_CONFIRMED_BIT, &ct->status); WRITE_UNLOCK(&ip_conntrack_lock); + ip_conntrack_stat[smp_processor_id()].insert++; return NF_ACCEPT; } WRITE_UNLOCK(&ip_conntrack_lock); + ip_conntrack_stat[smp_processor_id()].insert_failed++; return NF_DROP; } @@ -612,6 +625,7 @@ if (del_timer(&h->ctrack->timeout)) { death_by_timeout((unsigned long)h->ctrack); dropped = 1; + ip_conntrack_stat[smp_processor_id()].early_drop++; } ip_conntrack_put(h->ctrack); return dropped; @@ -735,12 +749,16 @@ LIST_DELETE(&ip_conntrack_expect_list, expected); expected->expectant->expecting--; nf_conntrack_get(&master_ct(conntrack)->infos[0]); - } + ip_conntrack_stat[smp_processor_id()].expect_new++; + } else + ip_conntrack_stat[smp_processor_id()].new++; + atomic_inc(&ip_conntrack_count); WRITE_UNLOCK(&ip_conntrack_lock); if (expected && expected->expectfn) expected->expectfn(conntrack); + return &conntrack->tuplehash[IP_CT_DIR_ORIGINAL]; } @@ -829,8 +847,10 @@ /* Previously seen (loopback)? Ignore. Do this before fragment check. */ - if ((*pskb)->nfct) + if ((*pskb)->nfct) { + ip_conntrack_stat[smp_processor_id()].ignore++; return NF_ACCEPT; + } /* Gather fragments. */ if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { @@ -843,12 +863,16 @@ /* It may be an icmp error... */ if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP - && icmp_error_track(*pskb, &ctinfo, hooknum)) + && icmp_error_track(*pskb, &ctinfo, hooknum)) { + ip_conntrack_stat[smp_processor_id()].icmp_error++; return NF_ACCEPT; + } - if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) + if (!(ct = resolve_normal_ct(*pskb, proto,&set_reply,hooknum,&ctinfo))) { /* Not valid part of a connection */ + ip_conntrack_stat[smp_processor_id()].invalid++; return NF_ACCEPT; + } if (IS_ERR(ct)) /* Too stressed to deal. */ @@ -860,6 +884,8 @@ if (ret < 0 ) { /* Invalid: inverse of the return code tells * to the netfilter core what to do. */ + if (ret == -NF_ACCEPT || ret == -NF_DROP) + ip_conntrack_stat[smp_processor_id()].invalid++; nf_conntrack_put((*pskb)->nfct); (*pskb)->nfct = NULL; return -ret; @@ -870,6 +896,7 @@ ct, ctinfo); if (ret == -1) { /* Invalid */ + ip_conntrack_stat[smp_processor_id()].invalid++; nf_conntrack_put((*pskb)->nfct); (*pskb)->nfct = NULL; return NF_ACCEPT; @@ -1052,6 +1079,8 @@ related_to->expecting++; WRITE_UNLOCK(&ip_conntrack_lock); + + ip_conntrack_stat[smp_processor_id()].expect_create++; return ret; } diff -urN linux-2.4.28-pre3-pomng-040917/net/ipv4/netfilter/ip_conntrack_standalone.c linux-2.4.28-pre3-pomng-040917-ctstat/net/ipv4/netfilter/ip_conntrack_standalone.c --- linux-2.4.28-pre3-pomng-040917/net/ipv4/netfilter/ip_conntrack_standalone.c Fri Sep 17 12:04:36 2004 +++ linux-2.4.28-pre3-pomng-040917-ctstat/net/ipv4/netfilter/ip_conntrack_standalone.c Fri Sep 17 13:15:11 2004 @@ -39,6 +39,9 @@ MODULE_LICENSE("GPL"); +extern atomic_t ip_conntrack_count; +extern struct ip_conntrack_stat ip_conntrack_stat[NR_CPUS]; + static int kill_proto(const struct ip_conntrack *i, void *data) { return (i->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum == @@ -179,6 +182,46 @@ return len; } +static int ip_conntrack_get_stat(char *buffer, char **start, off_t offset, int length) +{ + unsigned int nr_conntracks = atomic_read(&ip_conntrack_count); + int i, lcpu; + int len = 0; + + for (lcpu = 0; lcpu < smp_num_cpus; lcpu++) { + i = cpu_logical_map(lcpu); + + len += sprintf(buffer+len, "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x \n", + nr_conntracks, + ip_conntrack_stat[i].searched, + ip_conntrack_stat[i].found, + ip_conntrack_stat[i].new, + ip_conntrack_stat[i].invalid, + ip_conntrack_stat[i].ignore, + ip_conntrack_stat[i].delete, + ip_conntrack_stat[i].delete_list, + ip_conntrack_stat[i].insert, + ip_conntrack_stat[i].insert_failed, + ip_conntrack_stat[i].drop, + ip_conntrack_stat[i].early_drop, + ip_conntrack_stat[i].icmp_error, + + ip_conntrack_stat[i].expect_new, + ip_conntrack_stat[i].expect_create, + ip_conntrack_stat[i].expect_delete + ); + } + len -= offset; + + if (len > length) + len = length; + if (len < 0) + len = 0; + + *start = buffer + offset; + return len; +} + static unsigned int ip_confirm(unsigned int hooknum, struct sk_buff **pskb, const struct net_device *in, @@ -360,7 +403,7 @@ #endif static int init_or_cleanup(int init) { - struct proc_dir_entry *proc; + struct proc_dir_entry *proc, *procstat; int ret = 0; if (!init) goto cleanup; @@ -373,10 +416,15 @@ if (!proc) goto cleanup_init; proc->owner = THIS_MODULE; + procstat = proc_net_create("ip_conntrack_stat", 0, ip_conntrack_get_stat); + if (!procstat) + goto cleanup_proc; + procstat->owner = THIS_MODULE; + ret = nf_register_hook(&ip_conntrack_in_ops); if (ret < 0) { printk("ip_conntrack: can't register pre-routing hook.\n"); - goto cleanup_proc; + goto cleanup_procstat; } ret = nf_register_hook(&ip_conntrack_local_out_ops); if (ret < 0) { @@ -421,6 +469,8 @@ ipfrag_flush(); local_bh_enable(); nf_unregister_hook(&ip_conntrack_in_ops); + cleanup_procstat: + proc_net_remove("ip_conntrack_stat"); cleanup_proc: proc_net_remove("ip_conntrack"); cleanup_init: