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);
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);
}
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,
};
*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_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)
{
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);
}
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,
};
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 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));
......
This diff is collapsed.
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