Commit 0d2cfd9d authored by Stephen Hemminger's avatar Stephen Hemminger

[IPVS]: Convert to seq_file.

parent c31c7015
......@@ -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 *cp, struct sk_buff *skb)
}
#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);
return list_entry(i, struct ip_vs_app, a_list);
}
}
return NULL;
}
pos += 64;
if (pos <= offset)
continue;
sprintf(temp, "%-3s %-7u %-6d %-17s",
static void ip_vs_app_seq_stop(struct seq_file *seq, void *v)
{
up(&__ip_vs_app_mutex);
}
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);
len += sprintf(buffer+len, "%-63s\n", temp);
if (pos >= offset+length)
goto done;
}
}
done:
up(&__ip_vs_app_mutex);
return 0;
}
*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 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 *skb, int pri,
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;
}
......
......@@ -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_conn_in_get
{
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, __u16 cport, __u32 vaddr, __u16 vport,
/*
* /proc/net/ip_vs_conn entries
*/
static int
ip_vs_conn_getinfo(char *buffer, char **start, off_t offset, int length)
#ifdef CONFIG_PROC_FS
#define SEQ_START_TOKEN ((void *)1)
static void *ip_vs_conn_array(struct seq_file *seq, loff_t pos)
{
off_t pos=0;
int idx, len=0;
char temp[70];
struct ip_vs_conn *cp;
struct list_head *l, *e;
struct list_head *e;
int idx;
loff_t off = 0;
pos = 128;
if (pos > offset) {
len += sprintf(buffer+len, "%-127s\n",
"Pro FromIP FPrt ToIP TPrt DestIP DPrt State Expires");
for(idx = 0; idx < IP_VS_CONN_TAB_SIZE; idx++) {
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);
}
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.
*/
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;
}
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",
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);
}
return 0;
}
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;
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));
......
......@@ -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_table = {
{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;
struct list_head *e;
/*
* 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");
/* look in hash by protocol */
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
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);
}
}
}
/* keep looking in fwmark */
for (idx = 0; idx < IP_VS_SVC_TAB_SIZE; idx++) {
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;
}
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;
}
/* print the service table hashed by <protocol,addr,port> */
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;
}
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;
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;
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;
}
/* print the service table hashed by 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) {
/* 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)
sprintf(temp2, "persistent %d %08X",
seq_printf(seq, "persistent %d %08X\n",
svc->timeout,
ntohl(svc->netmask));
else
temp2[0] = '\0';
seq_putc(seq, '\n');
sprintf(temp, "FWM %08X %s %s",
svc->fwmark,
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_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;
}
done:
read_unlock_bh(&__ip_vs_svc_lock);
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;
*start = buf+len-(pos-offset); /* Start of wanted data */
len = pos-offset;
if (len > length)
len = length;
if (len < 0)
len = 0;
return len;
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");
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);
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",
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 */
" Conns/s Pkts/s Pkts/s Bytes/s Bytes/s");
sprintf(temp, "%8X %8X %8X %16X %16X",
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);
}
*start = buf+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 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);
......
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