From 363c9612c2f286204248a57aafd87c089fdbd83a Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 27 Sep 2004 07:50:11 -0700 Subject: [TCP]: Fix congestion window expansion when using TSO. We only do congestion window expansion on full packet ACKs. We should do it for ACKs of sub-packets of a TSO frame as well. Signed-off-by: David S. Miller --- include/net/tcp.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index eb0f1970a40f..9709d4e7ca4e 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1180,7 +1180,8 @@ struct tcp_skb_cb { __u16 urg_ptr; /* Valid w/URG flags is set. */ __u32 ack_seq; /* Sequence number ACK'd */ - __u32 tso_factor; + __u16 tso_factor; /* If > 1, TSO frame */ + __u16 tso_mss; /* MSS that FACTOR's in terms of*/ }; #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) -- cgit v1.2.3 From bf19f71b39b2aeef87aa75d97ce079377ae5ecd7 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 27 Sep 2004 07:57:01 -0700 Subject: [NET]: Neighbour cache statistics like rt_stat. Add rtstat-like per-cpu statistics to the neighbour cache core. Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- include/net/neighbour.h | 31 +++++++++-- net/core/neighbour.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++- net/ipv6/ndisc.c | 4 +- 3 files changed, 171 insertions(+), 9 deletions(-) (limited to 'include') diff --git a/include/net/neighbour.h b/include/net/neighbour.h index e66c71da2357..40073cf19863 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -7,6 +7,11 @@ * Authors: * Pedro Roque * Alexey Kuznetsov + * + * Changes: + * + * Harald Welte: + * - Add neighbour cache statistics like rtstat */ /* The following flags & states are exported to user space, @@ -90,12 +95,25 @@ struct neigh_parms struct neigh_statistics { - unsigned long allocs; - unsigned long res_failed; - unsigned long rcv_probes_mcast; - unsigned long rcv_probes_ucast; + unsigned long allocs; /* number of allocated neighs */ + unsigned long destroys; /* number of destroyed neighs */ + unsigned long hash_grows; /* number of hash resizes */ + + unsigned long res_failed; /* nomber of failed resolutions */ + + unsigned long lookups; /* number of lookups */ + unsigned long hits; /* number of hits (among lookups) */ + + unsigned long rcv_probes_mcast; /* number of received mcast ipv6 */ + unsigned long rcv_probes_ucast; /* number of received ucast ipv6 */ + + unsigned long periodic_gc_runs; /* number of periodic GC runs */ + unsigned long forced_gc_runs; /* number of forced GC runs */ }; +#define NEIGH_CACHE_STAT_INC(tbl, field) \ + (per_cpu_ptr((tbl)->stats, smp_processor_id())->field++) + struct neighbour { struct neighbour *next; @@ -172,12 +190,15 @@ struct neigh_table unsigned long last_rand; struct neigh_parms *parms_list; kmem_cache_t *kmem_cachep; - struct neigh_statistics stats; + struct neigh_statistics *stats; struct neighbour **hash_buckets; unsigned int hash_mask; __u32 hash_rnd; unsigned int hash_chain_gc; struct pneigh_entry **phash_buckets; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pde; +#endif }; /* flags for neigh_update() */ diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 34bf8dee8cf9..5f4fca15aa94 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -12,6 +12,7 @@ * * Fixes: * Vitaly E. Lavrov releasing NULL neighbor in neigh_add. + * Harald Welte Add neighbour cache statistics like rtstat */ #include @@ -21,6 +22,7 @@ #include #include #include +#include #ifdef CONFIG_SYSCTL #include #endif @@ -59,6 +61,7 @@ void neigh_changeaddr(struct neigh_table *tbl, struct net_device *dev); static int neigh_glbl_allocs; static struct neigh_table *neigh_tables; +static struct file_operations neigh_stat_seq_fops; /* Neighbour hash table buckets are protected with rwlock tbl->lock. @@ -116,6 +119,8 @@ static int neigh_forced_gc(struct neigh_table *tbl) int shrunk = 0; int i; + NEIGH_CACHE_STAT_INC(tbl, forced_gc_runs); + write_lock_bh(&tbl->lock); for (i = 0; i <= tbl->hash_mask; i++) { struct neighbour *n, **np; @@ -273,7 +278,8 @@ static struct neighbour *neigh_alloc(struct neigh_table *tbl) init_timer(&n->timer); n->timer.function = neigh_timer_handler; n->timer.data = (unsigned long)n; - tbl->stats.allocs++; + + NEIGH_CACHE_STAT_INC(tbl, allocs); neigh_glbl_allocs++; tbl->entries++; n->tbl = tbl; @@ -315,6 +321,8 @@ static void neigh_hash_grow(struct neigh_table *tbl, unsigned long new_entries) struct neighbour **new_hash, **old_hash; unsigned int i, new_hash_mask, old_entries; + NEIGH_CACHE_STAT_INC(tbl, hash_grows); + BUG_ON(new_entries & (new_entries - 1)); new_hash = neigh_hash_alloc(new_entries); if (!new_hash) @@ -350,11 +358,14 @@ struct neighbour *neigh_lookup(struct neigh_table *tbl, const void *pkey, struct neighbour *n; int key_len = tbl->key_len; u32 hash_val = tbl->hash(pkey, dev) & tbl->hash_mask; + + NEIGH_CACHE_STAT_INC(tbl, lookups); read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { if (dev == n->dev && !memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); + NEIGH_CACHE_STAT_INC(tbl, hits); break; } } @@ -368,10 +379,13 @@ struct neighbour *neigh_lookup_nodev(struct neigh_table *tbl, const void *pkey) int key_len = tbl->key_len; u32 hash_val = tbl->hash(pkey, NULL) & tbl->hash_mask; + NEIGH_CACHE_STAT_INC(tbl, lookups); + read_lock_bh(&tbl->lock); for (n = tbl->hash_buckets[hash_val]; n; n = n->next) { if (!memcmp(n->primary_key, pkey, key_len)) { neigh_hold(n); + NEIGH_CACHE_STAT_INC(tbl, hits); break; } } @@ -556,6 +570,8 @@ void neigh_destroy(struct neighbour *neigh) { struct hh_cache *hh; + NEIGH_CACHE_STAT_INC(neigh->tbl, destroys); + if (!neigh->dead) { printk(KERN_WARNING "Destroying alive neighbour %p\n", neigh); @@ -631,6 +647,8 @@ static void neigh_periodic_timer(unsigned long arg) struct neighbour *n, **np; unsigned long expire, now = jiffies; + NEIGH_CACHE_STAT_INC(tbl, periodic_gc_runs); + write_lock(&tbl->lock); /* @@ -762,7 +780,7 @@ static void neigh_timer_handler(unsigned long arg) neigh->nud_state = NUD_FAILED; notify = 1; - neigh->tbl->stats.res_failed++; + NEIGH_CACHE_STAT_INC(neigh->tbl, res_failed); NEIGH_PRINTK2("neigh %p is failed.\n", neigh); /* It is very thin place. report_unreachable is very complicated @@ -1311,6 +1329,29 @@ void neigh_table_init(struct neigh_table *tbl) if (!tbl->kmem_cachep) panic("cannot create neighbour cache"); + tbl->stats = alloc_percpu(struct neigh_statistics); + if (!tbl->stats) + panic("cannot create neighbour cache statistics"); + +#ifdef CONFIG_PROC_FS +#define NC_STAT_SUFFIX "_stat" + { + char *proc_stat_name; + proc_stat_name = kmalloc(strlen(tbl->id) + + strlen(NC_STAT_SUFFIX) + 1, GFP_KERNEL); + if (!proc_stat_name) + panic("cannot allocate neighbour cache proc name buffer"); + strcpy(proc_stat_name, tbl->id); + strcat(proc_stat_name, NC_STAT_SUFFIX); + + tbl->pde = create_proc_entry(proc_stat_name, 0, proc_net); + if (!tbl->pde) + panic("cannot create neighbour proc dir entry"); + tbl->pde->proc_fops = &neigh_stat_seq_fops; + tbl->pde->data = tbl; + } +#endif + tbl->hash_mask = 1; tbl->hash_buckets = neigh_hash_alloc(tbl->hash_mask + 1); @@ -1857,6 +1898,106 @@ void neigh_seq_stop(struct seq_file *seq, void *v) } EXPORT_SYMBOL(neigh_seq_stop); +/* statistics via seq_file */ + +static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + int cpu; + + if (*pos == 0) + return SEQ_START_TOKEN; + + for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu+1; + return per_cpu_ptr(tbl->stats, cpu); + } + return NULL; +} + +static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + int cpu; + + for (cpu = *pos; cpu < NR_CPUS; ++cpu) { + if (!cpu_possible(cpu)) + continue; + *pos = cpu+1; + return per_cpu_ptr(tbl->stats, cpu); + } + return NULL; +} + +static void neigh_stat_seq_stop(struct seq_file *seq, void *v) +{ + +} + +static int neigh_stat_seq_show(struct seq_file *seq, void *v) +{ + struct proc_dir_entry *pde = seq->private; + struct neigh_table *tbl = pde->data; + struct neigh_statistics *st = v; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "entries allocs destroys hash_grows lookups hits res_failed rcv_probes_mcast rcv_probes_ucast periodic_gc_runs forced_gc_runs forced_gc_goal_miss\n"); + return 0; + } + + seq_printf(seq, "%08x %08lx %08lx %08lx %08lx %08lx %08lx " + "%08lx %08lx %08lx %08lx\n", + tbl->entries, + + st->allocs, + st->destroys, + st->hash_grows, + + st->lookups, + st->hits, + + st->res_failed, + + st->rcv_probes_mcast, + st->rcv_probes_ucast, + + st->periodic_gc_runs, + st->forced_gc_runs + ); + + return 0; +} + +static struct seq_operations neigh_stat_seq_ops = { + .start = neigh_stat_seq_start, + .next = neigh_stat_seq_next, + .stop = neigh_stat_seq_stop, + .show = neigh_stat_seq_show, +}; + +static int neigh_stat_seq_open(struct inode *inode, struct file *file) +{ + int ret = seq_open(file, &neigh_stat_seq_ops); + + if (!ret) { + struct seq_file *sf = file->private_data; + sf->private = PDE(inode); + } + return ret; +}; + +static struct file_operations neigh_stat_seq_fops = { + .owner = THIS_MODULE, + .open = neigh_stat_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + #endif /* CONFIG_PROC_FS */ #ifdef CONFIG_ARPD diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index 3ed60fb4f11e..685a02d2ebf5 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -802,9 +802,9 @@ static void ndisc_recv_ns(struct sk_buff *skb) } if (inc) - nd_tbl.stats.rcv_probes_mcast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_mcast); else - nd_tbl.stats.rcv_probes_ucast++; + NEIGH_CACHE_STAT_INC(&nd_tbl, rcv_probes_ucast); /* * update / create cache entry -- cgit v1.2.3 From 23c834301dd71f7f818decfe9dc6cc4205549795 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Mon, 27 Sep 2004 23:26:54 -0700 Subject: [TCP]: Uninline tcp_current_mss(). Also fix the return value of tcp_sync_mss() to be unsigned. Signed-off-by: David S. Miller --- include/net/tcp.h | 34 ++-------------------------------- net/ipv4/tcp_output.c | 32 +++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 33 deletions(-) (limited to 'include') diff --git a/include/net/tcp.h b/include/net/tcp.h index 9709d4e7ca4e..68e15e26d7ed 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -961,7 +961,8 @@ extern void tcp_clear_xmit_timers(struct sock *); extern void tcp_delete_keepalive_timer (struct sock *); extern void tcp_reset_keepalive_timer (struct sock *, unsigned long); -extern int tcp_sync_mss(struct sock *sk, u32 pmtu); +extern unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu); +extern unsigned int tcp_current_mss(struct sock *sk, int large); extern const char timer_bug_msg[]; @@ -1035,37 +1036,6 @@ static inline void tcp_reset_xmit_timer(struct sock *sk, int what, unsigned long }; } -/* Compute the current effective MSS, taking SACKs and IP options, - * and even PMTU discovery events into account. - * - * LARGESEND note: !urg_mode is overkill, only frames up to snd_up - * cannot be large. However, taking into account rare use of URG, this - * is not a big flaw. - */ - -static inline unsigned int tcp_current_mss(struct sock *sk, int large) -{ - struct tcp_opt *tp = tcp_sk(sk); - struct dst_entry *dst = __sk_dst_get(sk); - int do_large, mss_now; - - do_large = (large && - (sk->sk_route_caps & NETIF_F_TSO) && - !tp->urg_mode); - mss_now = do_large ? tp->mss_cache : tp->mss_cache_std; - - if (dst) { - u32 mtu = dst_pmtu(dst); - if (mtu != tp->pmtu_cookie || - tp->ext2_header_len != dst->header_len) - mss_now = tcp_sync_mss(sk, mtu); - } - if (tp->eff_sacks) - mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + - (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); - return mss_now; -} - /* Initialize RCV_MSS value. * RCV_MSS is an our guess about MSS used by the peer. * We haven't any direct information about the MSS. diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index eaf28d8b584f..85518e0b4e83 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -603,7 +603,7 @@ static inline int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len) this function. --ANK (980731) */ -int tcp_sync_mss(struct sock *sk, u32 pmtu) +unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu) { struct tcp_opt *tp = tcp_sk(sk); struct dst_entry *dst = __sk_dst_get(sk); @@ -661,6 +661,36 @@ int tcp_sync_mss(struct sock *sk, u32 pmtu) return mss_now; } +/* Compute the current effective MSS, taking SACKs and IP options, + * and even PMTU discovery events into account. + * + * LARGESEND note: !urg_mode is overkill, only frames up to snd_up + * cannot be large. However, taking into account rare use of URG, this + * is not a big flaw. + */ + +unsigned int tcp_current_mss(struct sock *sk, int large) +{ + struct tcp_opt *tp = tcp_sk(sk); + struct dst_entry *dst = __sk_dst_get(sk); + int do_large, mss_now; + + do_large = (large && + (sk->sk_route_caps & NETIF_F_TSO) && + !tp->urg_mode); + mss_now = do_large ? tp->mss_cache : tp->mss_cache_std; + + if (dst) { + u32 mtu = dst_pmtu(dst); + if (mtu != tp->pmtu_cookie || + tp->ext2_header_len != dst->header_len) + mss_now = tcp_sync_mss(sk, mtu); + } + if (tp->eff_sacks) + mss_now -= (TCPOLEN_SACK_BASE_ALIGNED + + (tp->eff_sacks * TCPOLEN_SACK_PERBLOCK)); + return mss_now; +} /* This routine writes packets to the network. It advances the * send_head. This happens as incoming acks open up the remote -- cgit v1.2.3 From 5e78674021b427322a82c47c3826ea18b2480854 Mon Sep 17 00:00:00 2001 From: Thomas Graf Date: Mon, 27 Sep 2004 23:59:09 -0700 Subject: [PKT_SCHED]: Report qdisc parent to userspace Report parent classid of a qdisc back to userspace. Without this there is no way for userspace to see if the qdisc is attached to a class other than parsing all class trees of the link and check all tcm_info fields in the leaf classes. Signed-off-by: Thomas Graf Signed-off-by: David S. Miller --- include/net/pkt_sched.h | 1 + net/sched/sch_api.c | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'include') diff --git a/include/net/pkt_sched.h b/include/net/pkt_sched.h index bce3aaf91235..c632d5408275 100644 --- a/include/net/pkt_sched.h +++ b/include/net/pkt_sched.h @@ -80,6 +80,7 @@ struct Qdisc int padded; struct Qdisc_ops *ops; u32 handle; + u32 parent; atomic_t refcnt; struct sk_buff_head q; struct net_device *dev; diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index ebb9935ab4ca..5da7b7312642 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -371,6 +371,8 @@ int qdisc_graft(struct net_device *dev, struct Qdisc *parent, u32 classid, unsigned long cl = cops->get(parent, classid); if (cl) { err = cops->graft(parent, cl, new, old); + if (new) + new->parent = classid; cops->put(parent, cl); } } @@ -821,7 +823,7 @@ static int tc_dump_qdisc(struct sk_buff *skb, struct netlink_callback *cb) q_idx++; continue; } - if (tc_fill_qdisc(skb, q, 0, NETLINK_CB(cb->skb).pid, + if (tc_fill_qdisc(skb, q, q->parent, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWQDISC) <= 0) { read_unlock_bh(&qdisc_tree_lock); goto done; -- cgit v1.2.3 From 6ad5331ee3c59d40eb8a52078823a0921c83dfa8 Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Tue, 28 Sep 2004 00:22:31 -0700 Subject: [NET]: Generic network statistics This patch moves the following files in /proc: /proc/net/rt_cache_stat /proc/net/stat/rt_cache /proc/net/ip_conntrack_stat /proc/net/stat/ip_conntrack /proc/net/arp_cache_stat /proc/net/stat/arp_cache /proc/net/clip_arp_cache_stat /proc/net/stat/clip_arp_cache /proc/net/dn_neigh_cache_stat /proc/net/stat/dn_neigh_cache This allows a generic statistics tool to scan for all available statistics by doing readdir(2) on /proc/net/stat It also adds a special first 'template' line to rt_cache and ip_conntrack in order to facilitate compatibility once somebody adds new fields to the output lines. WARNING: This breaks existing rtstat.c and ctstat.c userspace programs (hopefully for the last time). rtstat is non-existant or broken in major distributions anyway, and ctstat is too new for any distros having it picked up. Therefore, we justify this breakage. A new unified statistics tool for routing cache, connection tracking and neighbour cache is under development and will be included with iproute2. Signed-off-by: Harald Welte Signed-off-by: David S. Miller --- fs/proc/root.c | 5 ++++- include/linux/proc_fs.h | 1 + net/core/neighbour.c | 13 +------------ net/ipv4/netfilter/ip_conntrack_standalone.c | 21 +++++++++++++++------ net/ipv4/route.c | 24 ++++++++++++++++++------ 5 files changed, 39 insertions(+), 25 deletions(-) (limited to 'include') diff --git a/fs/proc/root.c b/fs/proc/root.c index 4ece27d02514..6151f0592f28 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -18,7 +18,7 @@ #include #include -struct proc_dir_entry *proc_net, *proc_bus, *proc_root_fs, *proc_root_driver; +struct proc_dir_entry *proc_net, *proc_net_stat, *proc_bus, *proc_root_fs, *proc_root_driver; #ifdef CONFIG_SYSCTL struct proc_dir_entry *proc_sys_root; @@ -53,6 +53,8 @@ void __init proc_root_init(void) } proc_misc_init(); proc_net = proc_mkdir("net", NULL); + proc_net_stat = proc_mkdir("net/stat", NULL); + #ifdef CONFIG_SYSVIPC proc_mkdir("sysvipc", NULL); #endif @@ -157,5 +159,6 @@ EXPORT_SYMBOL(remove_proc_entry); EXPORT_SYMBOL(proc_root); EXPORT_SYMBOL(proc_root_fs); EXPORT_SYMBOL(proc_net); +EXPORT_SYMBOL(proc_net_stat); EXPORT_SYMBOL(proc_bus); EXPORT_SYMBOL(proc_root_driver); diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index abcfc4bca268..c83dd15b728c 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -79,6 +79,7 @@ struct kcore_list { extern struct proc_dir_entry proc_root; extern struct proc_dir_entry *proc_root_fs; extern struct proc_dir_entry *proc_net; +extern struct proc_dir_entry *proc_net_stat; extern struct proc_dir_entry *proc_bus; extern struct proc_dir_entry *proc_root_driver; extern struct proc_dir_entry *proc_root_kcore; diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 5f4fca15aa94..a5509ef5570e 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -1334,22 +1334,11 @@ void neigh_table_init(struct neigh_table *tbl) panic("cannot create neighbour cache statistics"); #ifdef CONFIG_PROC_FS -#define NC_STAT_SUFFIX "_stat" - { - char *proc_stat_name; - proc_stat_name = kmalloc(strlen(tbl->id) + - strlen(NC_STAT_SUFFIX) + 1, GFP_KERNEL); - if (!proc_stat_name) - panic("cannot allocate neighbour cache proc name buffer"); - strcpy(proc_stat_name, tbl->id); - strcat(proc_stat_name, NC_STAT_SUFFIX); - - tbl->pde = create_proc_entry(proc_stat_name, 0, proc_net); + tbl->pde = create_proc_entry(tbl->id, 0, proc_net_stat); if (!tbl->pde) panic("cannot create neighbour proc dir entry"); tbl->pde->proc_fops = &neigh_stat_seq_fops; tbl->pde->data = tbl; - } #endif tbl->hash_mask = 1; diff --git a/net/ipv4/netfilter/ip_conntrack_standalone.c b/net/ipv4/netfilter/ip_conntrack_standalone.c index dbd569b58dcd..9abaf01a72cc 100644 --- a/net/ipv4/netfilter/ip_conntrack_standalone.c +++ b/net/ipv4/netfilter/ip_conntrack_standalone.c @@ -268,10 +268,13 @@ static void *ct_cpu_seq_start(struct seq_file *seq, loff_t *pos) { int cpu; - for (cpu = *pos; cpu < NR_CPUS; ++cpu) { + if (*pos == 0) + return SEQ_START_TOKEN; + + for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { if (!cpu_possible(cpu)) continue; - *pos = cpu; + *pos = cpu+1; return &per_cpu(ip_conntrack_stat, cpu); } @@ -282,10 +285,10 @@ static void *ct_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) { int cpu; - for (cpu = *pos + 1; cpu < NR_CPUS; ++cpu) { + for (cpu = *pos; cpu < NR_CPUS; ++cpu) { if (!cpu_possible(cpu)) continue; - *pos = cpu; + *pos = cpu+1; return &per_cpu(ip_conntrack_stat, cpu); } @@ -301,6 +304,11 @@ static int ct_cpu_seq_show(struct seq_file *seq, void *v) unsigned int nr_conntracks = atomic_read(&ip_conntrack_count); struct ip_conntrack_stat *st = v; + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "entries searched found new invalid ignore delete delete_list insert insert_failed drop early_drop icmp_error expect_new expect_create expect_delete\n"); + return 0; + } + seq_printf(seq, "%08x %08x %08x %08x %08x %08x %08x %08x " "%08x %08x %08x %08x %08x %08x %08x %08x \n", nr_conntracks, @@ -735,10 +743,11 @@ static int init_or_cleanup(int init) &exp_file_ops); if (!proc_exp) goto cleanup_proc; - proc_stat = proc_net_fops_create("ip_conntrack_stat", S_IRUGO, - &ct_cpu_seq_fops); + proc_stat = create_proc_entry("ip_conntrack", S_IRUGO, proc_net_stat); if (!proc_stat) goto cleanup_proc_exp; + + proc_stat->proc_fops = &ct_cpu_seq_fops; proc_stat->owner = THIS_MODULE; #endif diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 73b19d735c90..455cc0e77549 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -356,10 +356,13 @@ static void *rt_cpu_seq_start(struct seq_file *seq, loff_t *pos) { int cpu; - for (cpu = *pos; cpu < NR_CPUS; ++cpu) { + if (*pos == 0) + return SEQ_START_TOKEN; + + for (cpu = *pos-1; cpu < NR_CPUS; ++cpu) { if (!cpu_possible(cpu)) continue; - *pos = cpu; + *pos = cpu+1; return per_cpu_ptr(rt_cache_stat, cpu); } return NULL; @@ -369,10 +372,10 @@ static void *rt_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos) { int cpu; - for (cpu = *pos + 1; cpu < NR_CPUS; ++cpu) { + for (cpu = *pos; cpu < NR_CPUS; ++cpu) { if (!cpu_possible(cpu)) continue; - *pos = cpu; + *pos = cpu+1; return per_cpu_ptr(rt_cache_stat, cpu); } return NULL; @@ -387,6 +390,11 @@ static void rt_cpu_seq_stop(struct seq_file *seq, void *v) static int rt_cpu_seq_show(struct seq_file *seq, void *v) { struct rt_cache_stat *st = v; + + if (v == SEQ_START_TOKEN) { + seq_printf(seq, "entries in_hit in_slow_tot in_no_route in_brd in_martian_dst in_martian_src out_hit out_slow_tot out_slow_mc gc_total gc_ignored gc_goal_miss gc_dst_overflow in_hlist_search out_hlist_search\n"); + return 0; + } seq_printf(seq,"%08x %08x %08x %08x %08x %08x %08x %08x " " %08x %08x %08x %08x %08x %08x %08x %08x %08x \n", @@ -2783,12 +2791,16 @@ int __init ip_rt_init(void) add_timer(&rt_secret_timer); #ifdef CONFIG_PROC_FS + { + struct proc_dir_entry *rtstat_pde = NULL; /* keep gcc happy */ if (!proc_net_fops_create("rt_cache", S_IRUGO, &rt_cache_seq_fops) || - !proc_net_fops_create("rt_cache_stat", S_IRUGO, &rt_cpu_seq_fops)) { + !(rtstat_pde = create_proc_entry("rt_cache", S_IRUGO, + proc_net_stat))) { free_percpu(rt_cache_stat); return -ENOMEM; } - + rtstat_pde->proc_fops = &rt_cpu_seq_fops; + } #ifdef CONFIG_NET_CLS_ROUTE create_proc_read_entry("rt_acct", 0, proc_net, ip_rt_acct_read, NULL); #endif -- cgit v1.2.3