netdev
[Top] [All Lists]

[PATCH] Convert ipvs to use seq_file.

To: "David S. Miller" <davem@xxxxxxxxxx>
Subject: [PATCH] Convert ipvs to use seq_file.
From: Stephen Hemminger <shemminger@xxxxxxxx>
Date: Mon, 15 Sep 2003 14:39:57 -0700
Cc: lvs-users@xxxxxxxxxxxxxxxxxxxxxx, netdev@xxxxxxxxxxx
Organization: Open Source Development Lab
Sender: netdev-bounce@xxxxxxxxxxx
Convert IPVS (for 2.6.0-test5) to use seq_file for the /proc interface.
Got rid of gratuitous 64 column trailing blank padding.

P.s: how come there is no MAINTAINER listed for IPVS?

diff -urNp -X dontdiff linux-2.5/net/ipv4/ipvs/ip_vs_app.c 
linux-2.5-net/net/ipv4/ipvs/ip_vs_app.c
--- linux-2.5/net/ipv4/ipvs/ip_vs_app.c 2003-09-15 09:57:15.000000000 -0700
+++ linux-2.5-net/net/ipv4/ipvs/ip_vs_app.c     2003-09-15 10:30:18.000000000 
-0700
@@ -35,6 +35,7 @@
 #include <asm/system.h>
 #include <linux/stat.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include <net/ip_vs.h>
 
@@ -480,55 +481,104 @@ int ip_vs_app_pkt_in(struct ip_vs_conn *
 }
 
 
+#ifdef CONFIG_PROC_FS
 /*
  *     /proc/net/ip_vs_app entry function
  */
-static int
-ip_vs_app_getinfo(char *buffer, char **start, off_t offset, int length)
+#define SEQ_START_TOKEN        ((void *)1)
+
+static struct ip_vs_app *ip_vs_app_idx(loff_t pos)
 {
-       off_t pos=0;
-       int len=0;
-       char temp[64];
-       struct ip_vs_app *app, *inc;
+       loff_t off = 0;
        struct list_head *e, *i;
 
-       pos = 64;
-       if (pos > offset) {
-               len += sprintf(buffer+len, "%-63s\n",
-                              "prot port    usecnt name");
+       list_for_each(e, &ip_vs_app_list) {
+               struct ip_vs_app *app
+                       = list_entry(e, struct ip_vs_app, a_list);
+               list_for_each (i, &app->incs_list) {
+                       if (off == pos)
+                               return list_entry(i, struct ip_vs_app, a_list);
+                       ++off;
+               }       
        }
+       return NULL;
+
+}
 
+static void *ip_vs_app_seq_start(struct seq_file *seq, loff_t *pos)
+{
        down(&__ip_vs_app_mutex);
-       list_for_each (e, &ip_vs_app_list) {
+       
+       return *pos ? ip_vs_app_idx(*pos - 1) : SEQ_START_TOKEN;
+}
+
+static void *ip_vs_app_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct ip_vs_app *inc, *app;
+       struct list_head *i, *e;
+
+       ++*pos;
+       if (v == SEQ_START_TOKEN)
+               return ip_vs_app_idx(0);
+       
+       inc = v;
+       app = inc->app;
+
+       if ((i = inc->a_list.next) != &app->incs_list)
+               return list_entry(i, struct ip_vs_app, a_list);
+
+       /* go on to next application */
+       for (e = app->a_list.next; e != &ip_vs_app_list; e = e->next) {
                app = list_entry(e, struct ip_vs_app, a_list);
                list_for_each (i, &app->incs_list) {
-                       inc = list_entry(i, struct ip_vs_app, a_list);
-
-                       pos += 64;
-                       if (pos <= offset)
-                               continue;
-                       sprintf(temp, "%-3s  %-7u %-6d %-17s",
-                               ip_vs_proto_name(inc->protocol),
-                               ntohs(inc->port),
-                               atomic_read(&inc->usecnt),
-                               inc->name);
-                       len += sprintf(buffer+len, "%-63s\n", temp);
-                       if (pos >= offset+length)
-                               goto done;
+                       return list_entry(i, struct ip_vs_app, a_list);
                }
        }
-  done:
+       return NULL;
+}
+
+static void ip_vs_app_seq_stop(struct seq_file *seq, void *v)
+{
        up(&__ip_vs_app_mutex);
+}
 
-       *start = buffer+len-(pos-offset);       /* Start of wanted data */
-       len = pos-offset;
-       if (len > length)
-               len = length;
-       if (len < 0)
-               len = 0;
-       return len;
+static int ip_vs_app_seq_show(struct seq_file *seq, void *v)
+{
+       if (v == SEQ_START_TOKEN)
+               seq_puts(seq, "prot port    usecnt name\n");
+       else {
+               const struct ip_vs_app *inc = v;
+
+               seq_printf(seq, "%-3s  %-7u %-6d %-17s\n",
+                          ip_vs_proto_name(inc->protocol),
+                          ntohs(inc->port),
+                          atomic_read(&inc->usecnt),
+                          inc->name);
+       }
+       return 0;
 }
 
+static struct seq_operations ip_vs_app_seq_ops = {
+       .start = ip_vs_app_seq_start,
+       .next  = ip_vs_app_seq_next,
+       .stop  = ip_vs_app_seq_stop,
+       .show  = ip_vs_app_seq_show,
+};
+
+static int ip_vs_app_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &ip_vs_app_seq_ops);
+}
+
+static struct file_operations ip_vs_app_fops = {
+       .owner   = THIS_MODULE,
+       .open    = ip_vs_app_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+#endif
+
 
 /*
  *     Replace a segment of data with a new segment
@@ -577,7 +627,7 @@ int ip_vs_skb_replace(struct sk_buff *sk
 int ip_vs_app_init(void)
 {
        /* we will replace it with proc_net_ipvs_create() soon */
-       proc_net_create("ip_vs_app", 0, ip_vs_app_getinfo);
+       proc_net_fops_create("ip_vs_app", 0, &ip_vs_app_fops);
        return 0;
 }
 
diff -urNp -X dontdiff linux-2.5/net/ipv4/ipvs/ip_vs_conn.c 
linux-2.5-net/net/ipv4/ipvs/ip_vs_conn.c
--- linux-2.5/net/ipv4/ipvs/ip_vs_conn.c        2003-09-15 09:57:15.000000000 
-0700
+++ linux-2.5-net/net/ipv4/ipvs/ip_vs_conn.c    2003-09-15 10:27:45.000000000 
-0700
@@ -30,6 +30,7 @@
 #include <linux/compiler.h>
 #include <linux/vmalloc.h>
 #include <linux/proc_fs.h>             /* for proc_net_* */
+#include <linux/seq_file.h>
 #include <linux/jhash.h>
 #include <linux/random.h>
 
@@ -188,14 +189,13 @@ static inline struct ip_vs_conn *__ip_vs
 {
        unsigned hash;
        struct ip_vs_conn *cp;
-       struct list_head *l,*e;
+       struct list_head *e;
 
        hash = ip_vs_conn_hashkey(protocol, s_addr, s_port);
-       l = &ip_vs_conn_tab[hash];
 
        ct_read_lock(hash);
 
-       for (e=l->next; e!=l; e=e->next) {
+       list_for_each(e, &ip_vs_conn_tab[hash]) {
                cp = list_entry(e, struct ip_vs_conn, c_list);
                if (s_addr==cp->caddr && s_port==cp->cport &&
                    d_port==cp->vport && d_addr==cp->vaddr &&
@@ -242,17 +242,16 @@ struct ip_vs_conn *ip_vs_conn_out_get
 {
        unsigned hash;
        struct ip_vs_conn *cp, *ret=NULL;
-       struct list_head *l,*e;
+       struct list_head *e;
 
        /*
         *      Check for "full" addressed entries
         */
        hash = ip_vs_conn_hashkey(protocol, d_addr, d_port);
-       l = &ip_vs_conn_tab[hash];
 
        ct_read_lock(hash);
 
-       for (e=l->next; e!=l; e=e->next) {
+       list_for_each(e, &ip_vs_conn_tab[hash]) {
                cp = list_entry(e, struct ip_vs_conn, c_list);
                if (d_addr == cp->caddr && d_port == cp->cport &&
                    s_port == cp->dport && s_addr == cp->daddr &&
@@ -615,61 +614,116 @@ ip_vs_conn_new(int proto, __u32 caddr, _
 /*
  *     /proc/net/ip_vs_conn entries
  */
-static int
-ip_vs_conn_getinfo(char *buffer, char **start, off_t offset, int length)
-{
-       off_t pos=0;
-       int idx, len=0;
-       char temp[70];
-       struct ip_vs_conn *cp;
-       struct list_head *l, *e;
+#ifdef CONFIG_PROC_FS
 
-       pos = 128;
-       if (pos > offset) {
-               len += sprintf(buffer+len, "%-127s\n",
-                              "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt 
State       Expires");
-       }
+#define SEQ_START_TOKEN        ((void *)1)
 
+static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
+{
+       struct list_head *e;
+       int idx;
+       loff_t off = 0;
+       
        for(idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {
-               /*
-                *      Lock is actually only need in next loop
-                *      we are called from uspace: must stop bh.
-                */
                ct_read_lock_bh(idx);
+               list_for_each(e, &ip_vs_conn_tab[idx]) {
+                       if (off == pos) {
+                               seq->private = &ip_vs_conn_tab[idx];
+                               return list_entry(e, struct ip_vs_conn, c_list);
+                       }
+                       ++off;
+               }       
+               ct_read_unlock_bh(idx);
+       }
 
-               l = &ip_vs_conn_tab[idx];
-               for (e=l->next; e!=l; e=e->next) {
-                       cp = list_entry(e, struct ip_vs_conn, c_list);
-                       pos += 128;
-                       if (pos <= offset)
-                               continue;
-                       sprintf(temp,
-                               "%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu",
+       return NULL;
+}
+
+static void *ip_vs_conn_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       seq->private = NULL;
+       return *pos ? ip_vs_conn_array(seq, *pos - 1) :SEQ_START_TOKEN;
+}
+
+static void *ip_vs_conn_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct ip_vs_conn *cp = v;
+       struct list_head *e, *l = seq->private;
+       int idx;
+
+       ++*pos;
+       if (v == SEQ_START_TOKEN) 
+               return ip_vs_conn_array(seq, 0);
+
+       /* more on same hash chain? */
+       if ((e = cp->c_list.next) != l)
+               return list_entry(e, struct ip_vs_conn, c_list);
+
+       idx = l - ip_vs_conn_tab;
+       ct_read_unlock_bh(idx);
+
+       while (++idx < IP_VS_CONN_TAB_SIZE) {
+               ct_read_lock_bh(idx);
+               list_for_each(e, &ip_vs_conn_tab[idx]) {
+                       seq->private = &ip_vs_conn_tab[idx];
+                       return list_entry(e, struct ip_vs_conn, c_list);
+               }       
+               ct_read_unlock_bh(idx);
+       }
+       seq->private = NULL;
+       return NULL;
+}
+
+static void ip_vs_conn_seq_stop(struct seq_file *seq, void *v)
+{
+       struct list_head *l = seq->private;
+
+       if (l) 
+               ct_read_unlock(l - ip_vs_conn_tab);
+}
+
+static int ip_vs_conn_seq_show(struct seq_file *seq, void *v)
+{
+
+       if (v == SEQ_START_TOKEN)
+               seq_puts(seq,
+   "Pro FromIP   FPrt ToIP     TPrt DestIP   DPrt State       Expires\n");
+       else {
+               const struct ip_vs_conn *cp = v;
+
+               seq_printf(seq,
+                       "%-3s %08X %04X %08X %04X %08X %04X %-11s %7lu\n",
                                ip_vs_proto_name(cp->protocol),
                                ntohl(cp->caddr), ntohs(cp->cport),
                                ntohl(cp->vaddr), ntohs(cp->vport),
                                ntohl(cp->daddr), ntohs(cp->dport),
                                ip_vs_state_name(cp->protocol, cp->state),
                                (cp->timer.expires-jiffies)/HZ);
-                       len += sprintf(buffer+len, "%-127s\n", temp);
-                       if (pos >= offset+length) {
-                               ct_read_unlock_bh(idx);
-                               goto done;
-                       }
-               }
-               ct_read_unlock_bh(idx);
        }
-
-  done:
-       *start = buffer+len-(pos-offset);       /* Start of wanted data */
-       len = pos-offset;
-       if (len > length)
-               len = length;
-       if (len < 0)
-               len = 0;
-       return len;
+       return 0;
 }
 
+static struct seq_operations ip_vs_conn_seq_ops = {
+       .start = ip_vs_conn_seq_start,
+       .next  = ip_vs_conn_seq_next,
+       .stop  = ip_vs_conn_seq_stop,
+       .show  = ip_vs_conn_seq_show,
+};
+
+static int ip_vs_conn_open(struct inode *inode, struct file *file)
+{
+       return seq_open(file, &ip_vs_conn_seq_ops);
+}
+
+static struct file_operations ip_vs_conn_fops = {
+       .owner   = THIS_MODULE,
+       .open    = ip_vs_conn_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release,
+};
+#endif
+
 
 /*
  *      Randomly drop connection entries before running out of memory
@@ -707,7 +761,7 @@ void ip_vs_random_dropentry(void)
 {
        int idx;
        struct ip_vs_conn *cp;
-       struct list_head *l,*e;
+       struct list_head *e;
        struct ip_vs_conn *ct;
 
        /*
@@ -721,8 +775,7 @@ void ip_vs_random_dropentry(void)
                 */
                ct_write_lock(hash);
 
-               l = &ip_vs_conn_tab[hash];
-               for (e=l->next; e!=l; e=e->next) {
+               list_for_each(e, &ip_vs_conn_tab[hash]) {
                        cp = list_entry(e, struct ip_vs_conn, c_list);
                        if (!cp->cport && !(cp->flags & IP_VS_CONN_F_NO_CPORT))
                                /* connection template */
@@ -775,7 +828,7 @@ static void ip_vs_conn_flush(void)
 {
        int idx;
        struct ip_vs_conn *cp;
-       struct list_head *l,*e;
+       struct list_head *e;
        struct ip_vs_conn *ct;
 
   flush_again:
@@ -785,8 +838,7 @@ static void ip_vs_conn_flush(void)
                 */
                ct_write_lock_bh(idx);
 
-               l = &ip_vs_conn_tab[idx];
-               for (e=l->next; e!=l; e=e->next) {
+               list_for_each(e, &ip_vs_conn_tab[idx]) {
                        cp = list_entry(e, struct ip_vs_conn, c_list);
                        atomic_inc(&cp->refcnt);
                        ct_write_unlock(idx);
@@ -848,7 +900,7 @@ int ip_vs_conn_init(void)
                __ip_vs_conntbl_lock_array[idx].l = RW_LOCK_UNLOCKED;
        }
 
-       proc_net_create("ip_vs_conn", 0, ip_vs_conn_getinfo);
+       proc_net_fops_create("ip_vs_conn", 0, &ip_vs_conn_fops);
 
        /* calculate the random value for connection hash */
        get_random_bytes(&ip_vs_conn_rnd, sizeof(ip_vs_conn_rnd));
diff -urNp -X dontdiff linux-2.5/net/ipv4/ipvs/ip_vs_ctl.c 
linux-2.5-net/net/ipv4/ipvs/ip_vs_ctl.c
--- linux-2.5/net/ipv4/ipvs/ip_vs_ctl.c 2003-09-15 09:57:15.000000000 -0700
+++ linux-2.5-net/net/ipv4/ipvs/ip_vs_ctl.c     2003-09-15 12:52:15.000000000 
-0700
@@ -31,6 +31,8 @@
 #include <linux/proc_fs.h>
 #include <linux/timer.h>
 #include <linux/swap.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4.h>
@@ -1507,207 +1509,253 @@ static struct ip_vs_sysctl_table ipv4_vs
         {0}}
 };
 
+#ifdef CONFIG_PROC_FS
+
+struct ip_vs_iter {
+       struct list_head *table;
+       int bucket;
+};
 
+
+#define SEQ_START_TOKEN        ((void *)1)
 /*
  *     Write the contents of the VS rule table to a PROCfs file.
  *     (It is kept just for backward compatibility)
  */
-static inline char *ip_vs_fwd_name(unsigned flags)
+static inline const char *ip_vs_fwd_name(unsigned flags)
 {
-       char *fwd;
-
        switch (flags & IP_VS_CONN_F_FWD_MASK) {
        case IP_VS_CONN_F_LOCALNODE:
-               fwd = "Local";
-               break;
+               return "Local";
        case IP_VS_CONN_F_TUNNEL:
-               fwd = "Tunnel";
-               break;
+               return "Tunnel";
        case IP_VS_CONN_F_DROUTE:
-               fwd = "Route";
-               break;
+               return "Route";
        default:
-               fwd = "Masq";
+               return "Masq";
        }
-       return fwd;
 }
 
-static inline int sprintf_dest(char *str, struct ip_vs_dest *dest)
-{
-       return sprintf(str, "  -> %08X:%04X      %-7s %-6d %-10d %-10d",
-                      ntohl(dest->addr), ntohs(dest->port),
-                      ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
-                      atomic_read(&dest->weight),
-                      atomic_read(&dest->activeconns),
-                      atomic_read(&dest->inactconns));
-}
 
-static int ip_vs_get_info(char *buf, char **start, off_t offset, int length)
+/* Get the Nth entry in the two lists */
+static struct ip_vs_service *ip_vs_info_array(struct seq_file *seq, loff_t pos)
 {
-       int len=0;
-       off_t pos=0;
-       char temp[64], temp2[32];
+       struct ip_vs_iter *iter = seq->private;
        int idx;
-       struct ip_vs_service *svc;
-       struct ip_vs_dest *dest;
-       struct list_head *l, *e, *p, *q;
-
-       /*
-        * Note: since the length of the buffer is usually the multiple
-        * of 512, it is good to use fixed record of the divisor of 512,
-        * so that records won't be truncated at buffer boundary.
-        */
-       pos = 192;
-       if (pos > offset) {
-               sprintf(temp,
-                       "IP Virtual Server version %d.%d.%d (size=%d)",
-                       NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);
-               len += sprintf(buf+len, "%-63s\n", temp);
-               len += sprintf(buf+len, "%-63s\n",
-                              "Prot LocalAddress:Port Scheduler Flags");
-               len += sprintf(buf+len, "%-63s\n",
-                              "  -> RemoteAddress:Port Forward Weight 
ActiveConn InActConn");
-       }
+       struct list_head *e;
 
-       read_lock_bh(&__ip_vs_svc_lock);
-
-       /* print the service table hashed by <protocol,addr,port> */
+       /* look in hash by protocol */
        for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-               l = &ip_vs_svc_table[idx];
-               for (e=l->next; e!=l; e=e->next) {
-                       svc = list_entry(e, struct ip_vs_service, s_list);
-                       pos += 64;
-                       if (pos > offset) {
-                               if (svc->flags & IP_VS_SVC_F_PERSISTENT)
-                                       sprintf(temp2, "persistent %d %08X",
-                                               svc->timeout,
-                                               ntohl(svc->netmask));
-                               else
-                                       temp2[0] = '\0';
-
-                               sprintf(temp, "%s  %08X:%04X %s %s",
-                                       ip_vs_proto_name(svc->protocol),
-                                       ntohl(svc->addr),
-                                       ntohs(svc->port),
-                                       svc->scheduler->name, temp2);
-                               len += sprintf(buf+len, "%-63s\n", temp);
-                               if (len >= length)
-                                       goto done;
-                       }
-
-                       p = &svc->destinations;
-                       for (q=p->next; q!=p; q=q->next) {
-                               dest = list_entry(q, struct ip_vs_dest, n_list);
-                               pos += 64;
-                               if (pos <= offset)
-                                       continue;
-                               sprintf_dest(temp, dest);
-                               len += sprintf(buf+len, "%-63s\n", temp);
-                               if (len >= length)
-                                       goto done;
+               list_for_each(e, &ip_vs_svc_table[idx]) {
+                       if (pos-- == 0){
+                               iter->table = ip_vs_svc_table;
+                               iter->bucket = idx;
+                               return list_entry(e, struct ip_vs_service, 
s_list);
                        }
                }
        }
 
-       /* print the service table hashed by fwmark */
+       /* keep looking in fwmark */
        for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
-               l = &ip_vs_svc_fwm_table[idx];
-               for (e=l->next; e!=l; e=e->next) {
-                       svc = list_entry(e, struct ip_vs_service, f_list);
-                       pos += 64;
-                       if (pos > offset) {
-                               if (svc->flags & IP_VS_SVC_F_PERSISTENT)
-                                       sprintf(temp2, "persistent %d %08X",
-                                               svc->timeout,
-                                               ntohl(svc->netmask));
-                               else
-                                       temp2[0] = '\0';
-
-                               sprintf(temp, "FWM  %08X %s %s",
-                                       svc->fwmark,
-                                       svc->scheduler->name, temp2);
-                               len += sprintf(buf+len, "%-63s\n", temp);
-                               if (len >= length)
-                                       goto done;
+               list_for_each(e, &ip_vs_svc_fwm_table[idx]) {
+                       if (pos-- == 0) {
+                               iter->table = ip_vs_svc_fwm_table;
+                               iter->bucket = idx;
+                               return list_entry(e, struct ip_vs_service, 
f_list);
                        }
+               }
+       }
+
+       return NULL;
+}
 
-                       p = &svc->destinations;
-                       for (q=p->next; q!=p; q=q->next) {
-                               dest = list_entry(q, struct ip_vs_dest, n_list);
-                               pos += 64;
-                               if (pos <= offset)
-                                       continue;
-                               sprintf_dest(temp, dest);
-                               len += sprintf(buf+len, "%-63s\n", temp);
-                               if (len >= length)
-                                       goto done;
+static void *ip_vs_info_seq_start(struct seq_file *seq, loff_t *pos)
+{
+
+       read_lock_bh(&__ip_vs_svc_lock);
+       return *pos ? ip_vs_info_array(seq, *pos - 1) : SEQ_START_TOKEN;
+}
+
+
+static void *ip_vs_info_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+       struct list_head *e;
+       struct ip_vs_iter *iter;
+       struct ip_vs_service *svc;
+
+       ++*pos;
+       if (v == SEQ_START_TOKEN)
+               return ip_vs_info_array(seq,0);
+       
+       svc = v;
+       iter = seq->private;
+       
+       if (iter->table == ip_vs_svc_table) {
+               /* next service in table hashed by protocol */
+               if ((e = svc->s_list.next) != &ip_vs_svc_table[iter->bucket])
+                       return list_entry(e, struct ip_vs_service, s_list);
+
+
+               while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
+                       list_for_each(e, &ip_vs_svc_table[iter->bucket]) {
+                               return list_entry(e, struct ip_vs_service, 
s_list);
                        }
                }
+
+               iter->table = ip_vs_svc_fwm_table;
+               iter->bucket = -1;
+               goto scan_fwmark;
        }
 
-  done:
+       /* next service in hashed by fwmark */
+       if ((e = svc->f_list.next) != &ip_vs_svc_fwm_table[iter->bucket])
+               return list_entry(e, struct ip_vs_service, f_list);
+
+ scan_fwmark:
+       while (++iter->bucket < IP_VS_SVC_TAB_SIZE) {
+               list_for_each(e, &ip_vs_svc_fwm_table[iter->bucket]) 
+                       return list_entry(e, struct ip_vs_service, f_list);
+       }
+
+       return NULL;
+}
+
+static void ip_vs_info_seq_stop(struct seq_file *seq, void *v)
+{
        read_unlock_bh(&__ip_vs_svc_lock);
+}
+
+
+static int ip_vs_info_seq_show(struct seq_file *seq, void *v)
+{
+       if (v == SEQ_START_TOKEN) {
+               seq_printf(seq,
+                       "IP Virtual Server version %d.%d.%d (size=%d)\n",
+                       NVERSION(IP_VS_VERSION_CODE), IP_VS_CONN_TAB_SIZE);
+               seq_puts(seq,
+                        "Prot LocalAddress:Port Scheduler Flags\n");
+               seq_puts(seq,
+                        "  -> RemoteAddress:Port Forward Weight ActiveConn 
InActConn\n");
+       } else {
+               const struct ip_vs_service *svc = v;
+               const struct ip_vs_iter *iter = seq->private;
+               const struct ip_vs_dest *dest;
+
+               if (iter->table == ip_vs_svc_table) 
+                       seq_printf(seq, "%s  %08X:%04X %s ",
+                                  ip_vs_proto_name(svc->protocol),
+                                  ntohl(svc->addr),
+                                  ntohs(svc->port),
+                                  svc->scheduler->name);
+               else
+                       seq_printf(seq, "FWM  %08X %s ",
+                                  svc->fwmark, svc->scheduler->name);
+
+               if (svc->flags & IP_VS_SVC_F_PERSISTENT)
+                       seq_printf(seq, "persistent %d %08X\n",
+                               svc->timeout,
+                               ntohl(svc->netmask));
+               else
+                       seq_putc(seq, '\n');
 
-       *start = buf+len-(pos-offset);          /* Start of wanted data */
-       len = pos-offset;
-       if (len > length)
-               len = length;
-       if (len < 0)
-               len = 0;
-       return len;
+               list_for_each_entry(dest, &svc->destinations, n_list) {
+                       seq_printf(seq, 
+                                  "  -> %08X:%04X      %-7s %-6d %-10d 
%-10d\n",
+                                  ntohl(dest->addr), ntohs(dest->port),
+                                  
ip_vs_fwd_name(atomic_read(&dest->conn_flags)),
+                                  atomic_read(&dest->weight),
+                                  atomic_read(&dest->activeconns),
+                                  atomic_read(&dest->inactconns));
+               }
+       }
+       return 0;
 }
 
+static struct seq_operations ip_vs_info_seq_ops = {
+       .start = ip_vs_info_seq_start,
+       .next  = ip_vs_info_seq_next,
+       .stop  = ip_vs_info_seq_stop,
+       .show  = ip_vs_info_seq_show,
+};
+
+static int ip_vs_info_open(struct inode *inode, struct file *file)
+{
+       struct seq_file *seq;
+       int rc = -ENOMEM;
+       struct ip_vs_iter *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+       if (!s)
+               goto out;
+
+       rc = seq_open(file, &ip_vs_info_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 ip_vs_info_fops = {
+       .owner   = THIS_MODULE,
+       .open    = ip_vs_info_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = seq_release_private,
+};
+
+#endif
 
 struct ip_vs_stats ip_vs_stats;
 
-static int
-ip_vs_stats_get_info(char *buf, char **start, off_t offset, int length)
+#ifdef CONFIG_PROC_FS
+static int ip_vs_stats_show(struct seq_file *seq, void *v)
 {
-       int len=0;
-       off_t pos=0;
-       char temp[64];
-
-       pos += 320;
-       if (pos > offset) {
-               len += sprintf(buf+len, "%-63s\n%-63s\n",
-/*                              01234567 01234567 01234567 0123456701234567 
0123456701234567 */
-                              "   Total Incoming Outgoing         Incoming     
    Outgoing",
-                              "   Conns  Packets  Packets            Bytes     
       Bytes");
-
-               spin_lock_bh(&ip_vs_stats.lock);
-               sprintf(temp, "%8X %8X %8X %8X%08X %8X%08X",
-                       ip_vs_stats.conns,
-                       ip_vs_stats.inpkts,
-                       ip_vs_stats.outpkts,
-                       (__u32)(ip_vs_stats.inbytes>>32),
-                       (__u32)ip_vs_stats.inbytes,
-                       (__u32)(ip_vs_stats.outbytes>>32),
-                       (__u32)ip_vs_stats.outbytes);
-               len += sprintf(buf+len, "%-62s\n\n", temp);
-
-               len += sprintf(buf+len, "%-63s\n",
-/*                              01234567 01234567 01234567 0123456701234567 
0123456701234567 */
-                              " Conns/s   Pkts/s   Pkts/s          Bytes/s     
     Bytes/s");
-               sprintf(temp, "%8X %8X %8X %16X %16X",
+
+/*               01234567 01234567 01234567 0123456701234567 0123456701234567 
*/
+       seq_puts(seq,
+                "   Total Incoming Outgoing         Incoming         
Outgoing\n");
+       seq_printf(seq,            
+                  "   Conns  Packets  Packets            Bytes            
Bytes\n");
+
+       spin_lock_bh(&ip_vs_stats.lock);
+       seq_printf(seq, "%8X %8X %8X %16LX %16LX\n\n", ip_vs_stats.conns,
+                  ip_vs_stats.inpkts, ip_vs_stats.outpkts,
+                  ip_vs_stats.inbytes, ip_vs_stats.outbytes);
+
+/*                 01234567 01234567 01234567 0123456701234567 
0123456701234567 */
+       seq_puts(seq,
+                  " Conns/s   Pkts/s   Pkts/s          Bytes/s          
Bytes/s\n");
+       seq_printf(seq,"%8X %8X %8X %16X %16X\n",
                        ip_vs_stats.cps,
                        ip_vs_stats.inpps,
                        ip_vs_stats.outpps,
                        ip_vs_stats.inbps,
                        ip_vs_stats.outbps);
-               len += sprintf(buf+len, "%-63s\n", temp);
+       spin_unlock_bh(&ip_vs_stats.lock);
 
-               spin_unlock_bh(&ip_vs_stats.lock);
-       }
+       return 0;
+}
 
-       *start = buf+len-(pos-offset);          /* Start of wanted data */
-       len = pos-offset;
-       if (len > length)
-               len = length;
-       if (len < 0)
-               len = 0;
-       return len;
+static int ip_vs_stats_seq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, ip_vs_stats_show, NULL);
 }
 
+static struct file_operations ip_vs_stats_fops = {
+       .owner = THIS_MODULE,
+       .open = ip_vs_stats_seq_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
+};
+
+#endif
 
 /*
  *     Set timeout values for tcp tcpfin udp in the timeout_table.
@@ -2195,8 +2243,8 @@ int ip_vs_control_init(void)
                return ret;
        }
 
-       proc_net_create("ip_vs", 0, ip_vs_get_info);
-       proc_net_create("ip_vs_stats", 0, ip_vs_stats_get_info);
+       proc_net_fops_create("ip_vs", 0, &ip_vs_info_fops);
+       proc_net_fops_create("ip_vs_stats",0, &ip_vs_stats_fops);
 
        ipv4_vs_table.sysctl_header =
                register_sysctl_table(ipv4_vs_table.root_dir, 0);

<Prev in Thread] Current Thread [Next in Thread>