]> git.hungrycats.org Git - linux/commitdiff
[IPV6] Convert /proc/net/ip6_flowlabel to seq_file.
authorHideaki Yoshifuji <yoshfuji@linux-ipv6.org>
Mon, 30 Jun 2003 06:40:01 +0000 (16:40 +1000)
committerHideaki Yoshifuji <yoshfuji@linux-ipv6.org>
Mon, 30 Jun 2003 06:40:01 +0000 (16:40 +1000)
net/ipv6/ip6_flowlabel.c

index f2d309fe7f1a00dbd4514325c41557b976e31126..58920fcb5c60a88be97e12199d039639d67c0aa5 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/in6.h>
 #include <linux/route.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include <net/sock.h>
 
@@ -554,66 +555,132 @@ done:
 
 #ifdef CONFIG_PROC_FS
 
+struct ip6fl_iter_state {
+       int bucket;
+};
 
-static int ip6_fl_read_proc(char *buffer, char **start, off_t offset,
-                           int length, int *eof, void *data)
-{
-       off_t pos=0;
-       off_t begin=0;
-       int len=0;
-       int i, k;
-       struct ip6_flowlabel *fl;
+#define ip6fl_seq_private(seq) ((struct ip6fl_iter_state *)&(seq)->private)
 
-       len+= sprintf(buffer,"Label S Owner  Users  Linger Expires  "
-                     "Dst                              Opt\n");
+static struct ip6_flowlabel *ip6fl_get_first(struct seq_file *seq)
+{
+       struct ip6_flowlabel *fl = NULL;
+       struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
 
-       read_lock_bh(&ip6_fl_lock);
-       for (i=0; i<=FL_HASH_MASK; i++) {
-               for (fl = fl_ht[i]; fl; fl = fl->next) {
-                       len+=sprintf(buffer+len,"%05X %-1d %-6d %-6d %-6d %-8ld ",
-                                    (unsigned)ntohl(fl->label),
-                                    fl->share,
-                                    (unsigned)fl->owner,
-                                    atomic_read(&fl->users),
-                                    fl->linger/HZ,
-                                    (long)(fl->expires - jiffies)/HZ);
-
-                       for (k=0; k<16; k++)
-                               len+=sprintf(buffer+len, "%02x", fl->dst.s6_addr[k]);
-                       buffer[len++]=' ';
-                       len+=sprintf(buffer+len, "%-4d", fl->opt ? fl->opt->opt_nflen : 0);
-                       buffer[len++]='\n';
-
-                       pos=begin+len;
-                       if(pos<offset) {
-                               len=0;
-                               begin=pos;
-                       }
-                       if(pos>offset+length)
-                               goto done;
+       for (state->bucket = 0; state->bucket <= FL_HASH_MASK; ++state->bucket) {
+               if (fl_ht[state->bucket]) {
+                       fl = fl_ht[state->bucket];
+                       break;
                }
        }
-       *eof = 1;
+       return fl;
+}
 
-done:
+static struct ip6_flowlabel *ip6fl_get_next(struct seq_file *seq, struct ip6_flowlabel *fl)
+{
+       struct ip6fl_iter_state *state = ip6fl_seq_private(seq);
+
+       fl = fl->next;
+       while (!fl) {
+               if (++state->bucket <= FL_HASH_MASK)
+                       fl = fl_ht[state->bucket];
+       }
+       return fl;
+}
+
+static struct ip6_flowlabel *ip6fl_get_idx(struct seq_file *seq, loff_t pos)
+{
+       struct ip6_flowlabel *fl = ip6fl_get_first(seq);
+       if (fl)
+               while (pos && (fl = ip6fl_get_next(seq, fl)) != NULL)
+                       --pos;
+       return pos ? NULL : fl;
+}
+
+static void *ip6fl_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       read_lock_bh(&ip6_fl_lock);
+       return *pos ? ip6fl_get_idx(seq, *pos) : (void *)1;
+}
+
+static void *ip6fl_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct ip6_flowlabel *fl;
+
+       if (v == (void *)1)
+               fl = ip6fl_get_first(seq);
+       else
+               fl = ip6fl_get_next(seq, v);
+       ++*pos;
+       return fl;
+}
+
+static void ip6fl_seq_stop(struct seq_file *seq, void *v)
+{
        read_unlock_bh(&ip6_fl_lock);
-       *start=buffer+(offset-begin);
-       len-=(offset-begin);
-       if(len>length)
-               len=length;
-       if(len<0)
-               len=0;
-       return len;
 }
+
+static void ip6fl_fl_seq_show(struct seq_file *seq, struct ip6_flowlabel *fl)
+{
+       while(fl) {
+               seq_printf(seq,
+                          "%05X %-1d %-6d %-6d %-6d %-8ld "
+                          "%02x%02x%02x%02x%02x%02x%02x%02x "
+                          "%-4d\n",
+                          (unsigned)ntohl(fl->label),
+                          fl->share,
+                          (unsigned)fl->owner,
+                          atomic_read(&fl->users),
+                          fl->linger/HZ,
+                          (long)(fl->expires - jiffies)/HZ,
+                          NIP6(fl->dst),
+                          fl->opt ? fl->opt->opt_nflen : 0);
+               fl = fl->next;
+       }
+}
+
+static int ip6fl_seq_show(struct seq_file *seq, void *v)
+{
+       if (v == (void *)1)
+               seq_printf(seq, "Label S Owner  Users  Linger Expires  "
+                               "Dst                              Opt\n");
+       else
+               ip6fl_fl_seq_show(seq, v);
+       return 0;
+}
+
+static struct seq_operations ip6fl_seq_ops = {
+       .start  =       ip6fl_seq_start,
+       .next   =       ip6fl_seq_next,
+       .stop   =       ip6fl_seq_stop,
+       .show   =       ip6fl_seq_show,
+};
+
+static int ip6fl_seq_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &ip6fl_seq_ops);
+}
+
+static struct file_operations ip6fl_seq_fops = {
+       .owner          =       THIS_MODULE,
+       .open           =       ip6fl_seq_open,
+       .read           =       seq_read,
+       .llseek         =       seq_lseek,
+       .release        =       seq_release,
+};
 #endif
 
 
 void ip6_flowlabel_init()
 {
+#ifdef CONFIG_PROC_FS
+       struct proc_dir_entry *p;
+#endif
        init_timer(&ip6_fl_gc_timer);
        ip6_fl_gc_timer.function = ip6_fl_gc;
 #ifdef CONFIG_PROC_FS
-       create_proc_read_entry("net/ip6_flowlabel", 0, 0, ip6_fl_read_proc, NULL);
+       p = create_proc_entry("ip6_flowlabel", S_IRUGO, proc_net);
+       if (p)
+               p->proc_fops = &ip6fl_seq_fops;
 #endif
 }
 
@@ -621,6 +688,6 @@ void ip6_flowlabel_cleanup()
 {
        del_timer(&ip6_fl_gc_timer);
 #ifdef CONFIG_PROC_FS
-       remove_proc_entry("net/ip6_flowlabel", 0);
+       proc_net_remove("ip6_flowlabel");
 #endif
 }