Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d50a6b56 authored by Stephen Hemminger's avatar Stephen Hemminger Committed by Arnaldo Carvalho de Melo
Browse files

[PKTGEN]: proc interface revision



The code to handle the /proc interface can be cleaned up in several places:
* use seq_file for read
* don't need to remember all the filenames separately
* use for_online_cpu's
* don't vmalloc a buffer for small command from user.

Committer note:
This patch clashed with John Hawkes's "[NET]: Wider use of for_each_*cpu()",
so I fixed it up manually.

Signed-off-by: default avatarStephen Hemminger <shemminger@osdl.org>
Signed-off-by: default avatarRobert Olsson <robert.olsson@its.uu.se>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
parent b4099fab
Loading
Loading
Loading
Loading
+215 −257
Original line number Diff line number Diff line
@@ -137,6 +137,7 @@
#include <linux/ipv6.h>
#include <linux/udp.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/wait.h>
#include <net/checksum.h>
#include <net/ipv6.h>
@@ -151,7 +152,7 @@
#include <asm/timex.h>


#define VERSION  "pktgen v2.62: Packet Generator for packet performance testing.\n"
#define VERSION  "pktgen v2.63: Packet Generator for packet performance testing.\n"

/* #define PG_DEBUG(a) a */
#define PG_DEBUG(a) 
@@ -186,7 +187,9 @@

/* Used to help with determining the pkts on receive */
#define PKTGEN_MAGIC 0xbe9be955
#define PG_PROC_DIR "net/pktgen"
#define PG_PROC_DIR "pktgen"
#define PGCTRL	    "pgctrl"
static struct proc_dir_entry *pg_proc_dir = NULL;

#define MAX_CFLOWS  65536

@@ -202,11 +205,8 @@ struct pktgen_dev {
	 * Try to keep frequent/infrequent used vars. separated.
	 */

        char ifname[32];
        struct proc_dir_entry *proc_ent;
        char ifname[IFNAMSIZ];
        char result[512];
        /* proc file names */
        char fname[80];

        struct pktgen_thread* pg_thread; /* the owner */
        struct pktgen_dev *next; /* Used for chaining in the thread's run-queue */
@@ -330,8 +330,6 @@ struct pktgen_thread {
        struct pktgen_dev *if_list;           /* All device here */
        struct pktgen_thread* next;
        char name[32];
        char fname[128]; /* name of proc file */
        struct proc_dir_entry *proc_ent;
        char result[512];
        u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
        
@@ -473,16 +471,6 @@ static inline __u64 tv_diff(const struct timeval* a, const struct timeval* b)

static char version[] __initdata = VERSION;

static ssize_t proc_pgctrl_read(struct file* file, char __user * buf, size_t count, loff_t *ppos);
static ssize_t proc_pgctrl_write(struct file* file, const char __user * buf, size_t count, loff_t *ppos);
static int proc_if_read(char *buf , char **start, off_t offset, int len, int *eof, void *data);

static int proc_thread_read(char *buf , char **start, off_t offset, int len, int *eof, void *data);
static int proc_if_write(struct file *file, const char __user *user_buffer, unsigned long count, void *data);
static int proc_thread_write(struct file *file, const char __user *user_buffer, unsigned long count, void *data);
static int create_proc_dir(void);
static int remove_proc_dir(void);

static int pktgen_remove_device(struct pktgen_thread* t, struct pktgen_dev *i);
static int pktgen_add_device(struct pktgen_thread* t, const char* ifname);
static struct pktgen_thread* pktgen_find_thread(const char* name);
@@ -506,80 +494,38 @@ static int debug = 0;
static DECLARE_MUTEX(pktgen_sem);
static struct pktgen_thread *pktgen_threads = NULL;

static char module_fname[128];
static struct proc_dir_entry *module_proc_ent = NULL;

static struct notifier_block pktgen_notifier_block = {
	.notifier_call = pktgen_device_event,
};

static struct file_operations pktgen_fops = {
        .read     = proc_pgctrl_read,
        .write    = proc_pgctrl_write,
	/*  .ioctl    = pktgen_ioctl, later maybe */
};

/*
 * /proc handling functions 
 *
 */

static struct proc_dir_entry *pg_proc_dir = NULL;
static int proc_pgctrl_read_eof=0;

static ssize_t proc_pgctrl_read(struct file* file, char __user * buf,
                                 size_t count, loff_t *ppos)
static int pgctrl_show(struct seq_file *seq, void *v)
{ 
	char data[200];
	int len = 0;

	if(proc_pgctrl_read_eof) {
		proc_pgctrl_read_eof=0;
		len = 0;
		goto out;
	}

	sprintf(data, "%s", VERSION); 

	len = strlen(data);

	if(len > count) {
		len = -EFAULT;
		goto out;
	}  	

	if (copy_to_user(buf, data, len)) {
		len = -EFAULT;
		goto out;
	}  

	*ppos += len;
	proc_pgctrl_read_eof=1; /* EOF next call */

 out:
	return len;
	seq_puts(seq, VERSION);
	return 0;
}

static ssize_t proc_pgctrl_write(struct file* file,const char __user * buf,
static ssize_t pgctrl_write(struct file* file,const char __user * buf,
			    size_t count, loff_t *ppos)
{
	char *data = NULL;
	int err = 0;
	char data[128];

        if (!capable(CAP_NET_ADMIN)){
                err = -EPERM;
		goto out;
        }

	data = (void*)vmalloc ((unsigned int)count);
	if (count > sizeof(data))
		count = sizeof(data);

	if(!data) {
		err = -ENOMEM;
		goto out;
	}
	if (copy_from_user(data, buf, count)) {
		err = -EFAULT;
		goto out_free;
		goto out;
	}  
	data[count-1] = 0; /* Make string */

@@ -594,31 +540,40 @@ static ssize_t proc_pgctrl_write(struct file* file,const char __user * buf,

	err = count;

 out_free:
	vfree (data);
 out:
        return err;
}

static int proc_if_read(char *buf , char **start, off_t offset,
                           int len, int *eof, void *data)
static int pgctrl_open(struct inode *inode, struct file *file)
{
	return single_open(file, pgctrl_show, PDE(inode)->data);
}

static struct file_operations pktgen_fops = {
	.owner	  = THIS_MODULE,
	.open	  = pgctrl_open,
        .read     = seq_read,
	.llseek	  = seq_lseek,
        .write    = pgctrl_write,
	.release  = single_release,
};

static int pktgen_if_show(struct seq_file *seq, void *v)
{
	char *p;
	int i;
        struct pktgen_dev *pkt_dev = (struct pktgen_dev*)(data);
        struct pktgen_dev *pkt_dev = seq->private;
        __u64 sa;
        __u64 stopped;
        __u64 now = getCurUs();
        
	p = buf;
	p += sprintf(p, "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
	seq_printf(seq, "Params: count %llu  min_pkt_size: %u  max_pkt_size: %u\n",
		   (unsigned long long) pkt_dev->count,
		   pkt_dev->min_pkt_size, pkt_dev->max_pkt_size);

	p += sprintf(p, "     frags: %d  delay: %u  clone_skb: %d  ifname: %s\n",
	seq_printf(seq, "     frags: %d  delay: %u  clone_skb: %d  ifname: %s\n",
		   pkt_dev->nfrags, 1000*pkt_dev->delay_us+pkt_dev->delay_ns, pkt_dev->clone_skb, pkt_dev->ifname);

	p += sprintf(p, "     flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow);
	seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows, pkt_dev->lflow);


	if(pkt_dev->flags & F_IPV6) {
@@ -626,19 +581,19 @@ static int proc_if_read(char *buf , char **start, off_t offset,
		fmt_ip6(b1,  pkt_dev->in6_saddr.s6_addr);
		fmt_ip6(b2,  pkt_dev->min_in6_saddr.s6_addr);
		fmt_ip6(b3,  pkt_dev->max_in6_saddr.s6_addr);
		p += sprintf(p, "     saddr: %s  min_saddr: %s  max_saddr: %s\n", b1, b2, b3);
		seq_printf(seq, "     saddr: %s  min_saddr: %s  max_saddr: %s\n", b1, b2, b3);

		fmt_ip6(b1,  pkt_dev->in6_daddr.s6_addr);
		fmt_ip6(b2,  pkt_dev->min_in6_daddr.s6_addr);
		fmt_ip6(b3,  pkt_dev->max_in6_daddr.s6_addr);
		p += sprintf(p, "     daddr: %s  min_daddr: %s  max_daddr: %s\n", b1, b2, b3);
		seq_printf(seq, "     daddr: %s  min_daddr: %s  max_daddr: %s\n", b1, b2, b3);

	} 
	else 
		p += sprintf(p, "     dst_min: %s  dst_max: %s\n     src_min: %s  src_max: %s\n",
		seq_printf(seq,"     dst_min: %s  dst_max: %s\n     src_min: %s  src_max: %s\n",
			   pkt_dev->dst_min, pkt_dev->dst_max, pkt_dev->src_min, pkt_dev->src_max);

        p += sprintf(p, "     src_mac: ");
	seq_puts(seq, "     src_mac: ");

	if ((pkt_dev->src_mac[0] == 0) && 
	    (pkt_dev->src_mac[1] == 0) && 
@@ -648,89 +603,89 @@ static int proc_if_read(char *buf , char **start, off_t offset,
	    (pkt_dev->src_mac[5] == 0)) 

		for (i = 0; i < 6; i++) 
			p += sprintf(p, "%02X%s", pkt_dev->odev->dev_addr[i], i == 5 ? "  " : ":");
			seq_printf(seq,  "%02X%s", pkt_dev->odev->dev_addr[i], i == 5 ? "  " : ":");

	else 
		for (i = 0; i < 6; i++) 
			p += sprintf(p, "%02X%s", pkt_dev->src_mac[i], i == 5 ? "  " : ":");
			seq_printf(seq,  "%02X%s", pkt_dev->src_mac[i], i == 5 ? "  " : ":");

        p += sprintf(p, "dst_mac: ");
        seq_printf(seq,  "dst_mac: ");
	for (i = 0; i < 6; i++) 
		p += sprintf(p, "%02X%s", pkt_dev->dst_mac[i], i == 5 ? "\n" : ":");
		seq_printf(seq,  "%02X%s", pkt_dev->dst_mac[i], i == 5 ? "\n" : ":");

        p += sprintf(p, "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
        seq_printf(seq,  "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
		   pkt_dev->udp_src_min, pkt_dev->udp_src_max, pkt_dev->udp_dst_min,
		   pkt_dev->udp_dst_max);

        p += sprintf(p, "     src_mac_count: %d  dst_mac_count: %d \n     Flags: ",
        seq_printf(seq,  "     src_mac_count: %d  dst_mac_count: %d \n     Flags: ",
		   pkt_dev->src_mac_count, pkt_dev->dst_mac_count);


        if (pkt_dev->flags &  F_IPV6) 
                p += sprintf(p, "IPV6  ");
                seq_printf(seq,  "IPV6  ");

        if (pkt_dev->flags &  F_IPSRC_RND) 
                p += sprintf(p, "IPSRC_RND  ");
                seq_printf(seq,  "IPSRC_RND  ");

        if (pkt_dev->flags & F_IPDST_RND) 
                p += sprintf(p, "IPDST_RND  ");
                seq_printf(seq,  "IPDST_RND  ");
        
        if (pkt_dev->flags & F_TXSIZE_RND) 
                p += sprintf(p, "TXSIZE_RND  ");
                seq_printf(seq,  "TXSIZE_RND  ");
        
        if (pkt_dev->flags & F_UDPSRC_RND) 
                p += sprintf(p, "UDPSRC_RND  ");
                seq_printf(seq,  "UDPSRC_RND  ");
        
        if (pkt_dev->flags & F_UDPDST_RND) 
                p += sprintf(p, "UDPDST_RND  ");
                seq_printf(seq,  "UDPDST_RND  ");
        
        if (pkt_dev->flags & F_MACSRC_RND) 
                p += sprintf(p, "MACSRC_RND  ");
                seq_printf(seq,  "MACSRC_RND  ");
        
        if (pkt_dev->flags & F_MACDST_RND) 
                p += sprintf(p, "MACDST_RND  ");
                seq_printf(seq,  "MACDST_RND  ");

        
        p += sprintf(p, "\n");
        seq_puts(seq,  "\n");
        
        sa = pkt_dev->started_at;
        stopped = pkt_dev->stopped_at;
        if (pkt_dev->running) 
                stopped = now; /* not really stopped, more like last-running-at */
        
        p += sprintf(p, "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %lluus  stopped: %lluus idle: %lluus\n",
        seq_printf(seq,  "Current:\n     pkts-sofar: %llu  errors: %llu\n     started: %lluus  stopped: %lluus idle: %lluus\n",
		   (unsigned long long) pkt_dev->sofar,
		   (unsigned long long) pkt_dev->errors,
		   (unsigned long long) sa,
		   (unsigned long long) stopped,
		   (unsigned long long) pkt_dev->idle_acc);

        p += sprintf(p, "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
                     pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset, pkt_dev->cur_src_mac_offset);
        seq_printf(seq,  "     seq_num: %d  cur_dst_mac_offset: %d  cur_src_mac_offset: %d\n",
		   pkt_dev->seq_num, pkt_dev->cur_dst_mac_offset,
		   pkt_dev->cur_src_mac_offset);

	if(pkt_dev->flags & F_IPV6) {
		char b1[128], b2[128];
		fmt_ip6(b1,  pkt_dev->cur_in6_daddr.s6_addr);
		fmt_ip6(b2,  pkt_dev->cur_in6_saddr.s6_addr);
		p += sprintf(p, "     cur_saddr: %s  cur_daddr: %s\n", b2, b1);
		seq_printf(seq,  "     cur_saddr: %s  cur_daddr: %s\n", b2, b1);
	} 
	else 
		p += sprintf(p, "     cur_saddr: 0x%x  cur_daddr: 0x%x\n",
		seq_printf(seq,  "     cur_saddr: 0x%x  cur_daddr: 0x%x\n",
			   pkt_dev->cur_saddr, pkt_dev->cur_daddr);


	p += sprintf(p, "     cur_udp_dst: %d  cur_udp_src: %d\n",
	seq_printf(seq,  "     cur_udp_dst: %d  cur_udp_src: %d\n",
		   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);

	p += sprintf(p, "     flows: %u\n", pkt_dev->nflows);
	seq_printf(seq,  "     flows: %u\n", pkt_dev->nflows);

	if (pkt_dev->result[0])
		p += sprintf(p, "Result: %s\n", pkt_dev->result);
		seq_printf(seq,  "Result: %s\n", pkt_dev->result);
	else
		p += sprintf(p, "Result: Idle\n");
	*eof = 1;
		seq_printf(seq,  "Result: Idle\n");

	return p - buf;
	return 0;
}


@@ -802,13 +757,14 @@ static int strn_len(const char __user *user_buffer, unsigned int maxlen)
	return i;
}

static int proc_if_write(struct file *file, const char __user *user_buffer,
                            unsigned long count, void *data)
static ssize_t pktgen_if_write(struct file *file, const char __user *user_buffer,
			       size_t count, loff_t *offset)
{
	struct seq_file *seq = (struct seq_file *) file->private_data;
        struct pktgen_dev *pkt_dev = seq->private;
	int i = 0, max, len;
	char name[16], valstr[32];
	unsigned long value = 0;
        struct pktgen_dev *pkt_dev = (struct pktgen_dev*)(data);
        char* pg_result = NULL;
        int tmp = 0;
	char buf[128];
@@ -849,7 +805,8 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
                if (copy_from_user(tb, user_buffer, count))
			return -EFAULT;
                tb[count] = 0;
		printk("pktgen: %s,%lu  buffer -:%s:-\n", name, count, tb);
		printk("pktgen: %s,%lu  buffer -:%s:-\n", name,
		       (unsigned long) count, tb);
        }

	if (!strcmp(name, "min_pkt_size")) {
@@ -1335,54 +1292,61 @@ static int proc_if_write(struct file *file, const char __user *user_buffer,
	return -EINVAL;
}

static int proc_thread_read(char *buf , char **start, off_t offset,
                               int len, int *eof, void *data)
static int pktgen_if_open(struct inode *inode, struct file *file)
{
	char *p;
        struct pktgen_thread *t = (struct pktgen_thread*)(data);
        struct pktgen_dev *pkt_dev = NULL;
	return single_open(file, pktgen_if_show, PDE(inode)->data);
}

static struct file_operations pktgen_if_fops = {
	.owner	  = THIS_MODULE,
	.open	  = pktgen_if_open,
        .read     = seq_read,
	.llseek	  = seq_lseek,
        .write    = pktgen_if_write,
	.release  = single_release,
};

        if (!t) {
                printk("pktgen: ERROR: could not find thread in proc_thread_read\n");
                return -EINVAL;
        }
static int pktgen_thread_show(struct seq_file *seq, void *v)
{
        struct pktgen_thread *t = seq->private;
        struct pktgen_dev *pkt_dev = NULL;

	BUG_ON(!t);

	p = buf;
	p += sprintf(p, "Name: %s  max_before_softirq: %d\n",
	seq_printf(seq, "Name: %s  max_before_softirq: %d\n",
                     t->name, t->max_before_softirq);

        p += sprintf(p, "Running: ");
        seq_printf(seq, "Running: ");
        
        if_lock(t);
        for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) 
		if(pkt_dev->running)
			p += sprintf(p, "%s ", pkt_dev->ifname);
			seq_printf(seq, "%s ", pkt_dev->ifname);
        
        p += sprintf(p, "\nStopped: ");
        seq_printf(seq, "\nStopped: ");

        for(pkt_dev = t->if_list;pkt_dev; pkt_dev = pkt_dev->next) 
		if(!pkt_dev->running)
			p += sprintf(p, "%s ", pkt_dev->ifname);
			seq_printf(seq, "%s ", pkt_dev->ifname);

	if (t->result[0])
		p += sprintf(p, "\nResult: %s\n", t->result);
		seq_printf(seq, "\nResult: %s\n", t->result);
	else
		p += sprintf(p, "\nResult: NA\n");

	*eof = 1;
		seq_printf(seq, "\nResult: NA\n");

        if_unlock(t);

	return p - buf;
	return 0;
}

static int proc_thread_write(struct file *file, const char __user *user_buffer,
                                unsigned long count, void *data)
static ssize_t pktgen_thread_write(struct file *file,
				   const char __user *user_buffer,
				   size_t count, loff_t *offset)
{
	struct seq_file *seq = (struct seq_file *) file->private_data;
        struct pktgen_thread *t = seq->private;
	int i = 0, max, len, ret;
	char name[40];
        struct pktgen_thread *t;
        char *pg_result;
        unsigned long value = 0;

@@ -1417,10 +1381,9 @@ static int proc_thread_write(struct file *file, const char __user *user_buffer,
	i += len;

	if (debug)
		printk("pktgen: t=%s, count=%lu\n", name, count);
        
		printk("pktgen: t=%s, count=%lu\n", name,
		       (unsigned long) count);

        t = (struct pktgen_thread*)(data);
	if(!t) {
		printk("pktgen: ERROR: No thread\n");
		ret = -EINVAL;
@@ -1474,21 +1437,19 @@ static int proc_thread_write(struct file *file, const char __user *user_buffer,
	return ret;
}

static int create_proc_dir(void)
static int pktgen_thread_open(struct inode *inode, struct file *file)
{
	pg_proc_dir = proc_mkdir(PG_PROC_DIR, NULL);
        
        if (!pg_proc_dir) 
                return -ENODEV;
        
        return 0;
	return single_open(file, pktgen_thread_show, PDE(inode)->data);
}

static int remove_proc_dir(void)
{
        remove_proc_entry(PG_PROC_DIR, NULL);
        return 0;
}
static struct file_operations pktgen_thread_fops = {
	.owner	  = THIS_MODULE,
	.open	  = pktgen_thread_open,
        .read     = seq_read,
	.llseek	  = seq_lseek,
        .write    = pktgen_thread_write,
	.release  = single_release,
};

/* Think find or remove for NN */
static struct pktgen_dev *__pktgen_NN_threads(const char* ifname, int remove) 
@@ -2552,8 +2513,7 @@ static void pktgen_rem_thread(struct pktgen_thread *t)

	struct pktgen_thread *tmp = pktgen_threads;

        if (strlen(t->fname))
                remove_proc_entry(t->fname, NULL);
	remove_proc_entry(t->name, pg_proc_dir);

	thread_lock();

@@ -2825,7 +2785,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, const char* i
        if_lock(t);

        for(pkt_dev=t->if_list; pkt_dev; pkt_dev = pkt_dev->next ) {
                if (strcmp(pkt_dev->ifname, ifname) == 0) {
                if (strncmp(pkt_dev->ifname, ifname, IFNAMSIZ) == 0) {
                        break;
                }
        }
@@ -2864,10 +2824,15 @@ static int add_dev_to_thread(struct pktgen_thread *t, struct pktgen_dev *pkt_dev
static int pktgen_add_device(struct pktgen_thread *t, const char* ifname) 
{
        struct pktgen_dev *pkt_dev;
	struct proc_dir_entry *pe;
	
	/* We don't allow a device to be on several threads */

	if( (pkt_dev = __pktgen_NN_threads(ifname, FIND)) == NULL) {
	pkt_dev = __pktgen_NN_threads(ifname, FIND);
	if (pkt_dev) {
                printk("pktgen: ERROR: interface already used.\n");
                return -EBUSY;
        }

	pkt_dev = kzalloc(sizeof(struct pktgen_dev), GFP_KERNEL);
	if (!pkt_dev)
@@ -2893,8 +2858,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char* ifname)
	pkt_dev->udp_dst_min = 9;
	pkt_dev->udp_dst_max = 9;

                strncpy(pkt_dev->ifname, ifname, 31);
                sprintf(pkt_dev->fname, "%s/%s", PG_PROC_DIR, ifname);
	strncpy(pkt_dev->ifname, ifname, IFNAMSIZ);

	if (! pktgen_setup_dev(pkt_dev)) {
		printk("pktgen: ERROR: pktgen_setup_dev failed.\n");
@@ -2904,26 +2868,20 @@ static int pktgen_add_device(struct pktgen_thread *t, const char* ifname)
		return -ENODEV;
	}

                pkt_dev->proc_ent = create_proc_entry(pkt_dev->fname, 0600, NULL);
                if (!pkt_dev->proc_ent) {
                        printk("pktgen: cannot create %s procfs entry.\n", pkt_dev->fname);
	pe = create_proc_entry(ifname, 0600, pg_proc_dir);
	if (!pe) {
		printk("pktgen: cannot create %s/%s procfs entry.\n",
		       PG_PROC_DIR, ifname);
		if (pkt_dev->flows)
			vfree(pkt_dev->flows);
		kfree(pkt_dev);
		return -EINVAL;
	}
                pkt_dev->proc_ent->read_proc = proc_if_read;
                pkt_dev->proc_ent->write_proc = proc_if_write;
                pkt_dev->proc_ent->data = (void*)(pkt_dev);
		pkt_dev->proc_ent->owner = THIS_MODULE;
	pe->proc_fops = &pktgen_if_fops;
	pe->data = pkt_dev;

	return add_dev_to_thread(t, pkt_dev);
}
        else {
                printk("pktgen: ERROR: interface already used.\n");
                return -EBUSY;
        }
}

static struct pktgen_thread *pktgen_find_thread(const char* name) 
{
@@ -2945,6 +2903,7 @@ static struct pktgen_thread *pktgen_find_thread(const char* name)
static int pktgen_create_thread(const char* name, int cpu) 
{
        struct pktgen_thread *t = NULL;
	struct proc_dir_entry *pe;

        if (strlen(name) > 31) {
                printk("pktgen: ERROR:  Thread name cannot be more than 31 characters.\n");
@@ -2966,17 +2925,16 @@ static int pktgen_create_thread(const char* name, int cpu)
        spin_lock_init(&t->if_lock);
	t->cpu = cpu;
        
        sprintf(t->fname, "%s/%s", PG_PROC_DIR, t->name);
        t->proc_ent = create_proc_entry(t->fname, 0600, NULL);
        if (!t->proc_ent) {
                printk("pktgen: cannot create %s procfs entry.\n", t->fname);
        pe = create_proc_entry(t->name, 0600, pg_proc_dir);
        if (!pe) {
                printk("pktgen: cannot create %s/%s procfs entry.\n",
		       PG_PROC_DIR, t->name);
                kfree(t);
                return -EINVAL;
        }
        t->proc_ent->read_proc = proc_thread_read;
        t->proc_ent->write_proc = proc_thread_write;
        t->proc_ent->data = (void*)(t);
        t->proc_ent->owner = THIS_MODULE;

	pe->proc_fops = &pktgen_thread_fops;
	pe->data = t;

        t->next = pktgen_threads;
        pktgen_threads = t;
@@ -3031,8 +2989,7 @@ static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *pkt_

        /* Clean up proc file system */

        if (strlen(pkt_dev->fname)) 
                remove_proc_entry(pkt_dev->fname, NULL);
	remove_proc_entry(pkt_dev->ifname, pg_proc_dir);

	if (pkt_dev->flows)
		vfree(pkt_dev->flows);
@@ -3043,21 +3000,24 @@ static int pktgen_remove_device(struct pktgen_thread *t, struct pktgen_dev *pkt_
static int __init pg_init(void) 
{
	int cpu;
	printk(version);
	struct proc_dir_entry *pe;

        module_fname[0] = 0;
	printk(version);

	create_proc_dir();
	pg_proc_dir = proc_mkdir(PG_PROC_DIR, proc_net);
	if (!pg_proc_dir)
		return -ENODEV;
	pg_proc_dir->owner = THIS_MODULE;

        sprintf(module_fname, "%s/pgctrl", PG_PROC_DIR);
        module_proc_ent = create_proc_entry(module_fname, 0600, NULL);
        if (!module_proc_ent) {
                printk("pktgen: ERROR: cannot create %s procfs entry.\n", module_fname);
	pe = create_proc_entry(PGCTRL, 0600, pg_proc_dir);
        if (pe == NULL) {
		printk("pktgen: ERROR: cannot create %s procfs entry.\n", PGCTRL);
		proc_net_remove(PG_PROC_DIR);
                return -EINVAL;
        }

        module_proc_ent->proc_fops =  &pktgen_fops;
        module_proc_ent->data = NULL;
        pe->proc_fops = &pktgen_fops;
        pe->data      = NULL;

	/* Register us to receive netdevice events */
	register_netdevice_notifier(&pktgen_notifier_block);
@@ -3089,10 +3049,8 @@ static void __exit pg_cleanup(void)
	unregister_netdevice_notifier(&pktgen_notifier_block);

        /* Clean up proc file system */

        remove_proc_entry(module_fname, NULL);
        
	remove_proc_dir();
	remove_proc_entry(PGCTRL, pg_proc_dir);
	proc_net_remove(PG_PROC_DIR);
}