summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@conectiva.com.br>2002-10-19 21:03:19 -0300
committerArnaldo Carvalho de Melo <acme@conectiva.com.br>2002-10-19 21:03:19 -0300
commit53008588b765cc238dd7b42a0455bb02df76cd39 (patch)
tree7084c793fed718a8b274f2ddfdd1317aa2ccdd09
parentecf2c2143f0865f447020144b2ee6e4181f65814 (diff)
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.
-rw-r--r--include/net/ip.h1
-rw-r--r--include/net/ip_fib.h2
-rw-r--r--net/ipv4/af_inet.c1
-rw-r--r--net/ipv4/fib_hash.c257
-rw-r--r--net/ipv4/fib_semantics.c41
-rw-r--r--net/ipv4/ip_proc.c74
6 files changed, 229 insertions, 147 deletions
diff --git a/include/net/ip.h b/include/net/ip.h
index 2d61d26fd188..bf14f1f50b90 100644
--- a/include/net/ip.h
+++ b/include/net/ip.h
@@ -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 */
diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h
index 01ac6fdd2617..debc59c4c240 100644
--- a/include/net/ip_fib.h
+++ b/include/net/ip_fib.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 */
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 3b76048f7b01..19b614a4ec2f 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1218,6 +1218,7 @@ static int __init inet_init(void)
#endif
ipv4_proc_init();
+ fib_proc_init();
return 0;
}
diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
index ac266c630436..05921a194fde 100644
--- a/net/ipv4/fib_hash.c
+++ b/net/ipv4/fib_hash.c
@@ -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 */
diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
index bfb3e7da150d..5d35417db3df 100644
--- a/net/ipv4/fib_semantics.c
+++ b/net/ipv4/fib_semantics.c
@@ -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
diff --git a/net/ipv4/ip_proc.c b/net/ipv4/ip_proc.c
index a115fc01ce0e..d909790861e8 100644
--- a/net/ipv4/ip_proc.c
+++ b/net/ipv4/ip_proc.c
@@ -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 @@ out_kfree:
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 @@ out_kfree:
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: