o ipv4: only produce one record per fib_seq_sholl call

Also move the fib code back to the fib implementation, and that will
now be done for udp and arp, then finally burying the ip_proc stillborn.
parent ecf2c214
......@@ -282,6 +282,7 @@ extern void ip_icmp_error(struct sock *sk, struct sk_buff *skb, int err,
extern void ip_local_error(struct sock *sk, int err, u32 daddr, u16 dport,
u32 info);
extern int ip_seq_release(struct inode *inode, struct file *file);
extern int ipv4_proc_init(void);
#endif /* _IP_H */
......@@ -129,7 +129,6 @@ struct fib_table
int (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
struct netlink_callback *cb);
int (*tb_flush)(struct fib_table *table);
int (*tb_seq_show)(struct fib_table *table, struct seq_file *seq);
void (*tb_select_default)(struct fib_table *table,
const struct flowi *flp, struct fib_result *res);
......@@ -277,5 +276,6 @@ static inline void fib_res_put(struct fib_result *res)
#endif
}
extern int fib_proc_init(void);
#endif /* _NET_FIB_H */
......@@ -1218,6 +1218,7 @@ static int __init inet_init(void)
#endif
ipv4_proc_init();
fib_proc_init();
return 0;
}
......
......@@ -745,37 +745,6 @@ static int fn_hash_flush(struct fib_table *tb)
}
#ifdef CONFIG_PROC_FS
static int fn_hash_seq_show(struct fib_table *tb, struct seq_file *seq)
{
struct fn_hash *table = (struct fn_hash *)tb->tb_data;
struct fn_zone *fz;
read_lock(&fib_hash_lock);
for (fz = table->fn_zone_list; fz; fz = fz->fz_next) {
int i;
struct fib_node *f;
int maxslot = fz->fz_divisor;
struct fib_node **fp = fz->fz_hash;
if (!fz->fz_nent)
continue;
for (i = 0; i < maxslot; i++, fp++)
for (f = *fp; f; f = f->fn_next)
fib_node_seq_show(seq, f->fn_type,
f->fn_state & FN_S_ZOMBIE,
FIB_INFO(f),
fz_prefix(f->fn_key, fz),
FZ_MASK(fz));
}
read_unlock(&fib_hash_lock);
return 0;
}
#endif
static __inline__ int
fn_hash_dump_bucket(struct sk_buff *skb, struct netlink_callback *cb,
struct fib_table *tb,
......@@ -897,9 +866,229 @@ struct fib_table * __init fib_hash_init(int id)
tb->tb_flush = fn_hash_flush;
tb->tb_select_default = fn_hash_select_default;
tb->tb_dump = fn_hash_dump;
#ifdef CONFIG_PROC_FS
tb->tb_seq_show = fn_hash_seq_show;
#endif
memset(tb->tb_data, 0, sizeof(struct fn_hash));
return tb;
}
/* ------------------------------------------------------------------------ */
#ifdef CONFIG_PROC_FS
struct fib_iter_state {
struct fn_zone *zone;
int bucket;
struct fib_node **hash;
struct fib_node *node;
};
static __inline__ struct fib_node *fib_get_first(struct seq_file *seq)
{
struct fib_iter_state* iter = seq->private;
struct fn_hash *table = (struct fn_hash *)ip_fib_main_table->tb_data;
iter->bucket = 0;
iter->hash = NULL;
iter->node = NULL;
for (iter->zone = table->fn_zone_list; iter->zone;
iter->zone = iter->zone->fz_next) {
int maxslot;
if (!iter->zone->fz_next)
continue;
iter->hash = iter->zone->fz_hash;
maxslot = iter->zone->fz_divisor;
for (iter->bucket = 0; iter->bucket < maxslot;
++iter->bucket, ++iter->hash) {
iter->node = *iter->hash;
if (iter->node)
goto out;
}
}
out:
return iter->node;
}
static __inline__ struct fib_node *fib_get_next(struct seq_file *seq)
{
struct fib_iter_state* iter = seq->private;
if (iter->node)
iter->node = iter->node->fn_next;
if (iter->node)
goto out;
if (!iter->zone)
goto out;
for (;;) {
int maxslot;
maxslot = iter->zone->fz_divisor;
while (++iter->bucket < maxslot) {
iter->node = *++iter->hash;
if (iter->node)
goto out;
}
for (;;) {
iter->zone = iter->zone->fz_next;
if (!iter->zone)
goto out;
if (iter->zone->fz_next);
break;
}
iter->hash = iter->zone->fz_hash;
iter->bucket = 0;
iter->node = *iter->hash;
if (iter->node)
break;
}
out:
return iter->node;
}
static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
{
void *v = NULL;
read_lock(&fib_hash_lock);
if (ip_fib_main_table)
v = *pos ? fib_get_next(seq) : (void *)1;
return v;
}
static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
++*pos;
return v == (void *)1 ? fib_get_first(seq) : fib_get_next(seq);
}
static void fib_seq_stop(struct seq_file *seq, void *v)
{
read_unlock(&fib_hash_lock);
}
static unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi)
{
static unsigned type2flags[RTN_MAX + 1] = {
[7] = RTF_REJECT, [8] = RTF_REJECT,
};
unsigned flags = type2flags[type];
if (fi && fi->fib_nh->nh_gw)
flags |= RTF_GATEWAY;
if (mask == 0xFFFFFFFF)
flags |= RTF_HOST;
if (!dead)
flags |= RTF_UP;
return flags;
}
/*
* This outputs /proc/net/route.
*
* It always works in backward compatibility mode.
* The format of the file is not supposed to be changed.
*/
static int fib_seq_show(struct seq_file *seq, void *v)
{
struct fib_iter_state* iter;
char bf[128];
u32 prefix, mask;
unsigned flags;
struct fib_node *f;
struct fib_info *fi;
if (v == (void *)1) {
seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "
"\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
"\tWindow\tIRTT");
goto out;
}
f = v;
fi = FIB_INFO(f);
iter = seq->private;
prefix = fz_prefix(f->fn_key, iter->zone);
mask = FZ_MASK(iter->zone);
flags = fib_flag_trans(f->fn_type, f->fn_state & FN_S_ZOMBIE,
mask, fi);
if (fi)
snprintf(bf, sizeof(bf),
"%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
fi->fib_dev ? fi->fib_dev->name : "*", prefix,
fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
mask, fi->fib_advmss + 40, fi->fib_window,
fi->fib_rtt >> 3);
else
snprintf(bf, sizeof(bf),
"*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0);
seq_printf(seq, "%-127s\n", bf);
out:
return 0;
}
static struct seq_operations fib_seq_ops = {
.start = fib_seq_start,
.next = fib_seq_next,
.stop = fib_seq_stop,
.show = fib_seq_show,
};
static int fib_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
int rc = -ENOMEM;
struct fib_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
goto out;
rc = seq_open(file, &fib_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 fib_seq_fops = {
.open = fib_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = ip_seq_release,
};
int __init fib_proc_init(void)
{
struct proc_dir_entry *p;
int rc = 0;
p = create_proc_entry("route", S_IRUGO, proc_net);
if (p)
p->proc_fops = &fib_seq_fops;
else
rc = -ENOMEM;
return rc;
}
#else /* CONFIG_PROC_FS */
int __init fib_proc_init(void)
{
return 0;
}
#endif /* CONFIG_PROC_FS */
......@@ -997,44 +997,3 @@ void fib_select_multipath(const struct flowi *flp, struct fib_result *res)
spin_unlock_bh(&fib_multipath_lock);
}
#endif
#ifdef CONFIG_PROC_FS
static unsigned fib_flag_trans(int type, int dead, u32 mask, struct fib_info *fi)
{
static unsigned type2flags[RTN_MAX+1] = {
0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0
};
unsigned flags = type2flags[type];
if (fi && fi->fib_nh->nh_gw)
flags |= RTF_GATEWAY;
if (mask == 0xFFFFFFFF)
flags |= RTF_HOST;
if (!dead)
flags |= RTF_UP;
return flags;
}
void fib_node_seq_show(struct seq_file *seq, int type, int dead,
struct fib_info *fi, u32 prefix, u32 mask)
{
char bf[128];
unsigned flags = fib_flag_trans(type, dead, mask, fi);
if (fi)
snprintf(bf, sizeof(bf),
"%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
fi->fib_dev ? fi->fib_dev->name : "*", prefix,
fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
mask, fi->fib_advmss + 40, fi->fib_window,
fi->fib_rtt >> 3);
else
snprintf(bf, sizeof(bf),
"*\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u",
prefix, 0, flags, 0, 0, 0, mask, 0, 0, 0);
seq_printf(seq, "%-127s\n", bf);
}
#endif
......@@ -21,7 +21,6 @@
#include <net/udp.h>
#include <linux/rtnetlink.h>
#include <linux/route.h>
#include <net/ip_fib.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
......@@ -250,38 +249,6 @@ static int arp_seq_show(struct seq_file *seq, void *v)
/* ------------------------------------------------------------------------ */
static void *fib_seq_start(struct seq_file *seq, loff_t *pos)
{
return *pos ? NULL : (void *)1;
}
static void *fib_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
return NULL;
}
static void fib_seq_stop(struct seq_file *seq, void *v)
{
}
/*
* This outputs /proc/net/route.
*
* It always works in backward compatibility mode.
* The format of the file is not supposed to be changed.
*/
static int fib_seq_show(struct seq_file *seq, void *v)
{
seq_printf(seq, "%-127s\n", "Iface\tDestination\tGateway "
"\tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU"
"\tWindow\tIRTT");
if (ip_fib_main_table)
ip_fib_main_table->tb_seq_show(ip_fib_main_table, seq);
return 0;
}
/* ------------------------------------------------------------------------ */
struct udp_iter_state {
int bucket;
};
......@@ -384,13 +351,6 @@ static struct seq_operations arp_seq_ops = {
.show = arp_seq_show,
};
static struct seq_operations fib_seq_ops = {
.start = fib_seq_start,
.next = fib_seq_next,
.stop = fib_seq_stop,
.show = fib_seq_show,
};
static struct seq_operations udp_seq_ops = {
.start = udp_seq_start,
.next = udp_seq_next,
......@@ -421,7 +381,7 @@ static int arp_seq_open(struct inode *inode, struct file *file)
goto out;
}
static int arp_seq_release(struct inode *inode, struct file *file)
int ip_seq_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = (struct seq_file *)file->private_data;
......@@ -431,11 +391,6 @@ static int arp_seq_release(struct inode *inode, struct file *file)
return seq_release(inode, file);
}
static int fib_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &fib_seq_ops);
}
static int udp_seq_open(struct inode *inode, struct file *file)
{
struct seq_file *seq;
......@@ -459,35 +414,18 @@ static int udp_seq_open(struct inode *inode, struct file *file)
goto out;
}
static int udp_seq_release(struct inode *inode, struct file *file)
{
struct seq_file *seq = (struct seq_file *)file->private_data;
kfree(seq->private);
seq->private = NULL;
return seq_release(inode, file);
}
static struct file_operations arp_seq_fops = {
.open = arp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = arp_seq_release,
};
static struct file_operations fib_seq_fops = {
.open = fib_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
.release = ip_seq_release,
};
static struct file_operations udp_seq_fops = {
.open = udp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = udp_seq_release,
.release = ip_seq_release,
};
/* ------------------------------------------------------------------------ */
......@@ -522,14 +460,8 @@ int __init ipv4_proc_init(void)
goto out_arp;
p->proc_fops = &arp_seq_fops;
p = create_proc_entry("route", S_IRUGO, proc_net);
if (!p)
goto out_route;
p->proc_fops = &fib_seq_fops;
out:
return rc;
out_route:
remove_proc_entry("route", proc_net);
out_arp:
remove_proc_entry("udp", proc_net);
out_udp:
......
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