Commit a9b7fa76 authored by Hideaki Yoshifuji's avatar Hideaki Yoshifuji Committed by David S. Miller

[IPV4/6]: Common TCP procfs infrastructure.

parent 26a2fcbd
...@@ -35,6 +35,7 @@ ...@@ -35,6 +35,7 @@
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
#include <linux/ipv6.h> #include <linux/ipv6.h>
#endif #endif
#include <linux/seq_file.h>
/* This is for all connections with a full identity, no wildcards. /* This is for all connections with a full identity, no wildcards.
* New scheme, half the table is for TIME_WAIT, the other half is * New scheme, half the table is for TIME_WAIT, the other half is
...@@ -1889,4 +1890,31 @@ static inline void tcp_mib_init(void) ...@@ -1889,4 +1890,31 @@ static inline void tcp_mib_init(void)
TCP_ADD_STATS_USER(TcpMaxConn, -1); TCP_ADD_STATS_USER(TcpMaxConn, -1);
} }
/* /proc */
enum tcp_seq_states {
TCP_SEQ_STATE_LISTENING,
TCP_SEQ_STATE_OPENREQ,
TCP_SEQ_STATE_ESTABLISHED,
TCP_SEQ_STATE_TIME_WAIT,
};
struct tcp_seq_afinfo {
struct module *owner;
char *name;
sa_family_t family;
int (*seq_show) (struct seq_file *m, void *v);
struct file_operations *seq_fops;
};
struct tcp_iter_state {
sa_family_t family;
enum tcp_seq_states state;
struct sock *syn_wait_sk;
int bucket, sbucket, num, uid;
struct seq_operations seq_ops;
};
extern int tcp_proc_register(struct tcp_seq_afinfo *afinfo);
extern void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo);
#endif /* _TCP_H */ #endif /* _TCP_H */
...@@ -1237,8 +1237,8 @@ extern void fib_proc_exit(void); ...@@ -1237,8 +1237,8 @@ extern void fib_proc_exit(void);
extern int ip_misc_proc_init(void); extern int ip_misc_proc_init(void);
extern int raw_proc_init(void); extern int raw_proc_init(void);
extern void raw_proc_exit(void); extern void raw_proc_exit(void);
extern int tcp_proc_init(void); extern int tcp4_proc_init(void);
extern void tcp_proc_exit(void); extern void tcp4_proc_exit(void);
extern int udp4_proc_init(void); extern int udp4_proc_init(void);
extern void udp4_proc_exit(void); extern void udp4_proc_exit(void);
...@@ -1248,7 +1248,7 @@ int __init ipv4_proc_init(void) ...@@ -1248,7 +1248,7 @@ int __init ipv4_proc_init(void)
if (raw_proc_init()) if (raw_proc_init())
goto out_raw; goto out_raw;
if (tcp_proc_init()) if (tcp4_proc_init())
goto out_tcp; goto out_tcp;
if (udp4_proc_init()) if (udp4_proc_init())
goto out_udp; goto out_udp;
...@@ -1263,7 +1263,7 @@ int __init ipv4_proc_init(void) ...@@ -1263,7 +1263,7 @@ int __init ipv4_proc_init(void)
out_fib: out_fib:
udp4_proc_exit(); udp4_proc_exit();
out_udp: out_udp:
tcp_proc_exit(); tcp4_proc_exit();
out_tcp: out_tcp:
raw_proc_exit(); raw_proc_exit();
out_raw: out_raw:
......
...@@ -2129,19 +2129,6 @@ static int tcp_v4_destroy_sock(struct sock *sk) ...@@ -2129,19 +2129,6 @@ static int tcp_v4_destroy_sock(struct sock *sk)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
/* Proc filesystem TCP sock list dumping. */ /* Proc filesystem TCP sock list dumping. */
enum tcp_seq_states {
TCP_SEQ_STATE_LISTENING,
TCP_SEQ_STATE_OPENREQ,
TCP_SEQ_STATE_ESTABLISHED,
TCP_SEQ_STATE_TIME_WAIT,
};
struct tcp_iter_state {
enum tcp_seq_states state;
struct sock *syn_wait_sk;
int bucket, sbucket, num, uid;
};
static void *listening_get_first(struct seq_file *seq) static void *listening_get_first(struct seq_file *seq)
{ {
struct tcp_iter_state* st = seq->private; struct tcp_iter_state* st = seq->private;
...@@ -2155,7 +2142,7 @@ static void *listening_get_first(struct seq_file *seq) ...@@ -2155,7 +2142,7 @@ static void *listening_get_first(struct seq_file *seq)
if (!sk) if (!sk)
continue; continue;
++st->num; ++st->num;
if (TCP_INET_FAMILY(sk->family)) { if (sk->family == st->family) {
rc = sk; rc = sk;
goto out; goto out;
} }
...@@ -2169,7 +2156,7 @@ static void *listening_get_first(struct seq_file *seq) ...@@ -2169,7 +2156,7 @@ static void *listening_get_first(struct seq_file *seq)
++st->sbucket) { ++st->sbucket) {
for (req = tp->listen_opt->syn_table[st->sbucket]; for (req = tp->listen_opt->syn_table[st->sbucket];
req; req = req->dl_next, ++st->num) { req; req = req->dl_next, ++st->num) {
if (!TCP_INET_FAMILY(req->class->family)) if (req->class->family != st->family)
continue; continue;
rc = req; rc = req;
goto out; goto out;
...@@ -2197,7 +2184,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) ...@@ -2197,7 +2184,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
while (1) { while (1) {
while (req) { while (req) {
++st->num; ++st->num;
if (TCP_INET_FAMILY(req->class->family)) { if (req->class->family == st->family) {
cur = req; cur = req;
goto out; goto out;
} }
...@@ -2215,7 +2202,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur) ...@@ -2215,7 +2202,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
sk = sk->next; sk = sk->next;
get_sk: get_sk:
while (sk) { while (sk) {
if (TCP_INET_FAMILY(sk->family)) { if (sk->family == st->family) {
cur = sk; cur = sk;
goto out; goto out;
} }
...@@ -2262,7 +2249,7 @@ static void *established_get_first(struct seq_file *seq) ...@@ -2262,7 +2249,7 @@ static void *established_get_first(struct seq_file *seq)
read_lock(&tcp_ehash[st->bucket].lock); read_lock(&tcp_ehash[st->bucket].lock);
for (sk = tcp_ehash[st->bucket].chain; sk; for (sk = tcp_ehash[st->bucket].chain; sk;
sk = sk->next, ++st->num) { sk = sk->next, ++st->num) {
if (!TCP_INET_FAMILY(sk->family)) if (sk->family != st->family)
continue; continue;
rc = sk; rc = sk;
goto out; goto out;
...@@ -2271,7 +2258,7 @@ static void *established_get_first(struct seq_file *seq) ...@@ -2271,7 +2258,7 @@ static void *established_get_first(struct seq_file *seq)
for (tw = (struct tcp_tw_bucket *) for (tw = (struct tcp_tw_bucket *)
tcp_ehash[st->bucket + tcp_ehash_size].chain; tcp_ehash[st->bucket + tcp_ehash_size].chain;
tw; tw = (struct tcp_tw_bucket *)tw->next, ++st->num) { tw; tw = (struct tcp_tw_bucket *)tw->next, ++st->num) {
if (!TCP_INET_FAMILY(tw->family)) if (tw->family != st->family)
continue; continue;
rc = tw; rc = tw;
goto out; goto out;
...@@ -2293,7 +2280,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) ...@@ -2293,7 +2280,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
tw = cur; tw = cur;
tw = (struct tcp_tw_bucket *)tw->next; tw = (struct tcp_tw_bucket *)tw->next;
get_tw: get_tw:
while (tw && !TCP_INET_FAMILY(tw->family)) { while (tw && tw->family != st->family) {
++st->num; ++st->num;
tw = (struct tcp_tw_bucket *)tw->next; tw = (struct tcp_tw_bucket *)tw->next;
} }
...@@ -2313,7 +2300,7 @@ static void *established_get_next(struct seq_file *seq, void *cur) ...@@ -2313,7 +2300,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
} else } else
sk = sk->next; sk = sk->next;
while (sk && !TCP_INET_FAMILY(sk->family)) { while (sk && sk->family != st->family) {
++st->num; ++st->num;
sk = sk->next; sk = sk->next;
} }
...@@ -2417,8 +2404,66 @@ static void tcp_seq_stop(struct seq_file *seq, void *v) ...@@ -2417,8 +2404,66 @@ static void tcp_seq_stop(struct seq_file *seq, void *v)
} }
} }
static void get_openreq(struct sock *sk, struct open_request *req, static int tcp_seq_open(struct inode *inode, struct file *file)
char *tmpbuf, int i, int uid) {
struct tcp_seq_afinfo *afinfo = PDE(inode)->data;
struct seq_file *seq;
int rc = -ENOMEM;
struct tcp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
memset(s, 0, sizeof(*s));
s->family = afinfo->family;
s->seq_ops.start = tcp_seq_start;
s->seq_ops.next = tcp_seq_next;
s->seq_ops.show = afinfo->seq_show;
s->seq_ops.stop = tcp_seq_stop;
rc = seq_open(file, &s->seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
out:
return rc;
out_kfree:
kfree(s);
goto out;
}
int tcp_proc_register(struct tcp_seq_afinfo *afinfo)
{
int rc = 0;
struct proc_dir_entry *p;
if (!afinfo)
return -EINVAL;
afinfo->seq_fops->owner = afinfo->owner;
afinfo->seq_fops->open = tcp_seq_open;
afinfo->seq_fops->read = seq_read;
afinfo->seq_fops->llseek = seq_lseek;
afinfo->seq_fops->release = seq_release_private;
p = create_proc_entry(afinfo->name, S_IRUGO, proc_net);
if (p) {
p->data = afinfo;
p->proc_fops = afinfo->seq_fops;
} else
rc = -ENOMEM;
return rc;
}
void tcp_proc_unregister(struct tcp_seq_afinfo *afinfo)
{
if (!afinfo)
return;
remove_proc_entry(afinfo->name, proc_net);
memset(afinfo->seq_fops, 0, sizeof(*afinfo->seq_fops));
}
static void get_openreq4(struct sock *sk, struct open_request *req,
char *tmpbuf, int i, int uid)
{ {
int ttd = req->expires - jiffies; int ttd = req->expires - jiffies;
...@@ -2441,7 +2486,7 @@ static void get_openreq(struct sock *sk, struct open_request *req, ...@@ -2441,7 +2486,7 @@ static void get_openreq(struct sock *sk, struct open_request *req,
req); req);
} }
static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i) static void get_tcp4_sock(struct sock *sp, char *tmpbuf, int i)
{ {
int timer_active; int timer_active;
unsigned long timer_expires; unsigned long timer_expires;
...@@ -2481,7 +2526,7 @@ static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i) ...@@ -2481,7 +2526,7 @@ static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i)
tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh); tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh);
} }
static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i) static void get_timewait4_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
{ {
unsigned int dest, src; unsigned int dest, src;
__u16 destp, srcp; __u16 destp, srcp;
...@@ -2504,7 +2549,7 @@ static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i) ...@@ -2504,7 +2549,7 @@ static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
#define TMPSZ 150 #define TMPSZ 150
static int tcp_seq_show(struct seq_file *seq, void *v) static int tcp4_seq_show(struct seq_file *seq, void *v)
{ {
struct tcp_iter_state* st; struct tcp_iter_state* st;
char tmpbuf[TMPSZ + 1]; char tmpbuf[TMPSZ + 1];
...@@ -2521,13 +2566,13 @@ static int tcp_seq_show(struct seq_file *seq, void *v) ...@@ -2521,13 +2566,13 @@ static int tcp_seq_show(struct seq_file *seq, void *v)
switch (st->state) { switch (st->state) {
case TCP_SEQ_STATE_LISTENING: case TCP_SEQ_STATE_LISTENING:
case TCP_SEQ_STATE_ESTABLISHED: case TCP_SEQ_STATE_ESTABLISHED:
get_tcp_sock(v, tmpbuf, st->num); get_tcp4_sock(v, tmpbuf, st->num);
break; break;
case TCP_SEQ_STATE_OPENREQ: case TCP_SEQ_STATE_OPENREQ:
get_openreq(st->syn_wait_sk, v, tmpbuf, st->num, st->uid); get_openreq4(st->syn_wait_sk, v, tmpbuf, st->num, st->uid);
break; break;
case TCP_SEQ_STATE_TIME_WAIT: case TCP_SEQ_STATE_TIME_WAIT:
get_timewait_sock(v, tmpbuf, st->num); get_timewait4_sock(v, tmpbuf, st->num);
break; break;
} }
seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf); seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);
...@@ -2535,57 +2580,23 @@ static int tcp_seq_show(struct seq_file *seq, void *v) ...@@ -2535,57 +2580,23 @@ static int tcp_seq_show(struct seq_file *seq, void *v)
return 0; return 0;
} }
static struct seq_operations tcp_seq_ops = { static struct file_operations tcp4_seq_fops;
.start = tcp_seq_start, static struct tcp_seq_afinfo tcp4_seq_afinfo = {
.next = tcp_seq_next, .owner = THIS_MODULE,
.stop = tcp_seq_stop, .name = "tcp",
.show = tcp_seq_show, .family = AF_INET,
}; .seq_show = tcp4_seq_show,
.seq_fops = &tcp4_seq_fops,
static int tcp_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct tcp_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &tcp_seq_ops);
if (rc)
goto out_kfree;
seq = file->private_data;
seq->private = s;
memset(s, 0, sizeof(*s));
out:
return rc;
out_kfree:
kfree(s);
goto out;
}
static struct file_operations tcp_seq_fops = {
.owner = THIS_MODULE,
.open = tcp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release_private,
}; };
int __init tcp_proc_init(void) int __init tcp4_proc_init(void)
{ {
int rc = 0; return tcp_proc_register(&tcp4_seq_afinfo);
struct proc_dir_entry *p = create_proc_entry("tcp", S_IRUGO, proc_net);
if (p)
p->proc_fops = &tcp_seq_fops;
else
rc = -ENOMEM;
return rc;
} }
void __init tcp_proc_exit(void) void tcp4_proc_exit(void)
{ {
remove_proc_entry("tcp", proc_net); tcp_proc_unregister(&tcp4_seq_afinfo);
} }
#endif /* CONFIG_PROC_FS */ #endif /* CONFIG_PROC_FS */
......
...@@ -285,6 +285,8 @@ EXPORT_SYMBOL(unregister_inetaddr_notifier); ...@@ -285,6 +285,8 @@ EXPORT_SYMBOL(unregister_inetaddr_notifier);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(udp_proc_register); EXPORT_SYMBOL(udp_proc_register);
EXPORT_SYMBOL(udp_proc_unregister); EXPORT_SYMBOL(udp_proc_unregister);
EXPORT_SYMBOL(tcp_proc_register);
EXPORT_SYMBOL(tcp_proc_unregister);
#endif #endif
/* needed for ip_gre -cw */ /* needed for ip_gre -cw */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment