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 @@
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
#include <linux/ipv6.h>
#endif
#include <linux/seq_file.h>
/* This is for all connections with a full identity, no wildcards.
* New scheme, half the table is for TIME_WAIT, the other half is
......@@ -1889,4 +1890,31 @@ static inline void tcp_mib_init(void)
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 */
......@@ -1237,8 +1237,8 @@ extern void fib_proc_exit(void);
extern int ip_misc_proc_init(void);
extern int raw_proc_init(void);
extern void raw_proc_exit(void);
extern int tcp_proc_init(void);
extern void tcp_proc_exit(void);
extern int tcp4_proc_init(void);
extern void tcp4_proc_exit(void);
extern int udp4_proc_init(void);
extern void udp4_proc_exit(void);
......@@ -1248,7 +1248,7 @@ int __init ipv4_proc_init(void)
if (raw_proc_init())
goto out_raw;
if (tcp_proc_init())
if (tcp4_proc_init())
goto out_tcp;
if (udp4_proc_init())
goto out_udp;
......@@ -1263,7 +1263,7 @@ int __init ipv4_proc_init(void)
out_fib:
udp4_proc_exit();
out_udp:
tcp_proc_exit();
tcp4_proc_exit();
out_tcp:
raw_proc_exit();
out_raw:
......
......@@ -2129,19 +2129,6 @@ static int tcp_v4_destroy_sock(struct sock *sk)
#ifdef CONFIG_PROC_FS
/* 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)
{
struct tcp_iter_state* st = seq->private;
......@@ -2155,7 +2142,7 @@ static void *listening_get_first(struct seq_file *seq)
if (!sk)
continue;
++st->num;
if (TCP_INET_FAMILY(sk->family)) {
if (sk->family == st->family) {
rc = sk;
goto out;
}
......@@ -2169,7 +2156,7 @@ static void *listening_get_first(struct seq_file *seq)
++st->sbucket) {
for (req = tp->listen_opt->syn_table[st->sbucket];
req; req = req->dl_next, ++st->num) {
if (!TCP_INET_FAMILY(req->class->family))
if (req->class->family != st->family)
continue;
rc = req;
goto out;
......@@ -2197,7 +2184,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
while (1) {
while (req) {
++st->num;
if (TCP_INET_FAMILY(req->class->family)) {
if (req->class->family == st->family) {
cur = req;
goto out;
}
......@@ -2215,7 +2202,7 @@ static void *listening_get_next(struct seq_file *seq, void *cur)
sk = sk->next;
get_sk:
while (sk) {
if (TCP_INET_FAMILY(sk->family)) {
if (sk->family == st->family) {
cur = sk;
goto out;
}
......@@ -2262,7 +2249,7 @@ static void *established_get_first(struct seq_file *seq)
read_lock(&tcp_ehash[st->bucket].lock);
for (sk = tcp_ehash[st->bucket].chain; sk;
sk = sk->next, ++st->num) {
if (!TCP_INET_FAMILY(sk->family))
if (sk->family != st->family)
continue;
rc = sk;
goto out;
......@@ -2271,7 +2258,7 @@ static void *established_get_first(struct seq_file *seq)
for (tw = (struct tcp_tw_bucket *)
tcp_ehash[st->bucket + tcp_ehash_size].chain;
tw; tw = (struct tcp_tw_bucket *)tw->next, ++st->num) {
if (!TCP_INET_FAMILY(tw->family))
if (tw->family != st->family)
continue;
rc = tw;
goto out;
......@@ -2293,7 +2280,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
tw = cur;
tw = (struct tcp_tw_bucket *)tw->next;
get_tw:
while (tw && !TCP_INET_FAMILY(tw->family)) {
while (tw && tw->family != st->family) {
++st->num;
tw = (struct tcp_tw_bucket *)tw->next;
}
......@@ -2313,7 +2300,7 @@ static void *established_get_next(struct seq_file *seq, void *cur)
} else
sk = sk->next;
while (sk && !TCP_INET_FAMILY(sk->family)) {
while (sk && sk->family != st->family) {
++st->num;
sk = sk->next;
}
......@@ -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,
char *tmpbuf, int i, int uid)
static int tcp_seq_open(struct inode *inode, struct file *file)
{
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;
......@@ -2441,7 +2486,7 @@ static void get_openreq(struct sock *sk, struct open_request *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;
unsigned long timer_expires;
......@@ -2481,7 +2526,7 @@ static void get_tcp_sock(struct sock *sp, char *tmpbuf, int i)
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;
__u16 destp, srcp;
......@@ -2504,7 +2549,7 @@ static void get_timewait_sock(struct tcp_tw_bucket *tw, char *tmpbuf, int i)
#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;
char tmpbuf[TMPSZ + 1];
......@@ -2521,13 +2566,13 @@ static int tcp_seq_show(struct seq_file *seq, void *v)
switch (st->state) {
case TCP_SEQ_STATE_LISTENING:
case TCP_SEQ_STATE_ESTABLISHED:
get_tcp_sock(v, tmpbuf, st->num);
get_tcp4_sock(v, tmpbuf, st->num);
break;
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;
case TCP_SEQ_STATE_TIME_WAIT:
get_timewait_sock(v, tmpbuf, st->num);
get_timewait4_sock(v, tmpbuf, st->num);
break;
}
seq_printf(seq, "%-*s\n", TMPSZ - 1, tmpbuf);
......@@ -2535,57 +2580,23 @@ static int tcp_seq_show(struct seq_file *seq, void *v)
return 0;
}
static struct seq_operations tcp_seq_ops = {
.start = tcp_seq_start,
.next = tcp_seq_next,
.stop = tcp_seq_stop,
.show = tcp_seq_show,
};
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,
static struct file_operations tcp4_seq_fops;
static struct tcp_seq_afinfo tcp4_seq_afinfo = {
.owner = THIS_MODULE,
.name = "tcp",
.family = AF_INET,
.seq_show = tcp4_seq_show,
.seq_fops = &tcp4_seq_fops,
};
int __init tcp_proc_init(void)
int __init tcp4_proc_init(void)
{
int rc = 0;
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;
return tcp_proc_register(&tcp4_seq_afinfo);
}
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 */
......
......@@ -285,6 +285,8 @@ EXPORT_SYMBOL(unregister_inetaddr_notifier);
#ifdef CONFIG_PROC_FS
EXPORT_SYMBOL(udp_proc_register);
EXPORT_SYMBOL(udp_proc_unregister);
EXPORT_SYMBOL(tcp_proc_register);
EXPORT_SYMBOL(tcp_proc_unregister);
#endif
/* 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