Merge branch 'e1000-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[pandora-kernel.git] / net / core / pktgen.c
index 1897a3a..b92a322 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * A tool for loading the network with preconfigurated packets.
- * The tool is implemented as a linux module.  Parameters are output 
+ * The tool is implemented as a linux module.  Parameters are output
  * device, delay (to hard_xmit), number of packets, and whether
  * to use multiple SKBs or just the same one.
  * pktgen uses the installed interface's output routine.
  *   *  Add IOCTL interface to easily get counters & configuration.
  *   --Ben Greear <greearb@candelatech.com>
  *
- * Renamed multiskb to clone_skb and cleaned up sending core for two distinct 
- * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0 
+ * Renamed multiskb to clone_skb and cleaned up sending core for two distinct
+ * skb modes. A clone_skb=0 mode for Ben "ranges" work and a clone_skb != 0
  * as a "fastpath" with a configurable number of clones after alloc's.
- * clone_skb=0 means all packets are allocated this also means ranges time 
- * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100 
+ * clone_skb=0 means all packets are allocated this also means ranges time
+ * stamps etc can be used. clone_skb=100 means 1 malloc is followed by 100
  * clones.
  *
- * Also moved to /proc/net/pktgen/ 
+ * Also moved to /proc/net/pktgen/
  * --ro
  *
  * Sept 10:  Fixed threading/locking.  Lots of bone-headed and more clever
  *
  * Integrated to 2.5.x 021029 --Lucio Maciel (luciomaciel@zipmail.com.br)
  *
- * 
+ *
  * 021124 Finished major redesign and rewrite for new functionality.
  * See Documentation/networking/pktgen.txt for how to use this.
  *
  * The new operation:
- * For each CPU one thread/process is created at start. This process checks 
- * for running devices in the if_list and sends packets until count is 0 it 
- * also the thread checks the thread->control which is used for inter-process 
- * communication. controlling process "posts" operations to the threads this 
+ * For each CPU one thread/process is created at start. This process checks
+ * for running devices in the if_list and sends packets until count is 0 it
+ * also the thread checks the thread->control which is used for inter-process
+ * communication. controlling process "posts" operations to the threads this
  * way. The if_lock should be possible to remove when add/rem_device is merged
  * into this too.
  *
- * By design there should only be *one* "controlling" process. In practice 
- * multiple write accesses gives unpredictable result. Understood by "write" 
+ * By design there should only be *one* "controlling" process. In practice
+ * multiple write accesses gives unpredictable result. Understood by "write"
  * to /proc gives result code thats should be read be the "writer".
  * For practical use this should be no problem.
  *
- * Note when adding devices to a specific CPU there good idea to also assign 
- * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU. 
+ * Note when adding devices to a specific CPU there good idea to also assign
+ * /proc/irq/XX/smp_affinity so TX-interrupts gets bound to the same CPU.
  * --ro
  *
- * Fix refcount off by one if first packet fails, potential null deref, 
+ * Fix refcount off by one if first packet fails, potential null deref,
  * memleak 030710- KJP
  *
  * First "ranges" functionality for ipv6 030726 --ro
  * Included flow support. 030802 ANK.
  *
  * Fixed unaligned access on IA-64 Grant Grundler <grundler@parisc-linux.org>
- * 
+ *
  * Remove if fix from added Harald Welte <laforge@netfilter.org> 040419
  * ia64 compilation fix from  Aron Griffis <aron@hp.com> 040604
  *
- * New xmit() return, do_div and misc clean up by Stephen Hemminger 
+ * New xmit() return, do_div and misc clean up by Stephen Hemminger
  * <shemminger@osdl.org> 040923
  *
- * Randy Dunlap fixed u64 printk compiler waring 
+ * Randy Dunlap fixed u64 printk compiler waring
  *
  * Remove FCS from BW calculation.  Lennert Buytenhek <buytenh@wantstofly.org>
  * New time handling. Lennert Buytenhek <buytenh@wantstofly.org> 041213
  *
- * Corrections from Nikolai Malykh (nmalykh@bilim.com) 
+ * Corrections from Nikolai Malykh (nmalykh@bilim.com)
  * Removed unused flags F_SET_SRCMAC & F_SET_SRCIP 041230
  *
- * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com> 
+ * interruptible_sleep_on_timeout() replaced Nishanth Aravamudan <nacc@us.ibm.com>
  * 050103
  *
  * MPLS support by Steven Whitehouse <steve@chygwyn.com>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/capability.h>
+#include <linux/freezer.h>
 #include <linux/delay.h>
 #include <linux/timer.h>
 #include <linux/list.h>
 #include <linux/seq_file.h>
 #include <linux/wait.h>
 #include <linux/etherdevice.h>
+#include <linux/kthread.h>
 #include <net/checksum.h>
 #include <net/ipv6.h>
 #include <net/addrconf.h>
 
 #define VERSION  "pktgen v2.68: Packet Generator for packet performance testing.\n"
 
-/* #define PG_DEBUG(a) a */
-#define PG_DEBUG(a)
-
 /* The buckets are exponential in 'width' */
 #define LAT_BUCKETS_MAX 32
 #define IP_NAME_SZ 32
 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
-#define MPLS_STACK_BOTTOM __constant_htonl(0x00000100)
+#define MPLS_STACK_BOTTOM htonl(0x00000100)
 
 /* Device flag bits */
 #define F_IPSRC_RND   (1<<0)   /* IP-Src Random  */
@@ -212,15 +211,11 @@ struct flow_state {
 };
 
 struct pktgen_dev {
-
        /*
         * Try to keep frequent/infrequent used vars. separated.
         */
-
-       char ifname[IFNAMSIZ];
-       char result[512];
-
-       struct pktgen_thread *pg_thread;        /* the owner */
+       struct proc_dir_entry *entry;   /* proc file */
+       struct pktgen_thread *pg_thread;/* the owner */
        struct list_head list;          /* Used for chaining in the thread's run-queue */
 
        int running;            /* if this changes to false, the test will stop */
@@ -347,6 +342,8 @@ struct pktgen_dev {
        unsigned cflows;        /* Concurrent flows (config) */
        unsigned lflow;         /* Flow length  (config) */
        unsigned nflows;        /* accumulated flows (stats) */
+
+       char result[512];
 };
 
 struct pktgen_hdr {
@@ -360,8 +357,7 @@ struct pktgen_thread {
        spinlock_t if_lock;
        struct list_head if_list;       /* All device here */
        struct list_head th_list;
-       int removed;
-       char name[32];
+       struct task_struct *tsk;
        char result[512];
        u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
 
@@ -456,7 +452,7 @@ static inline __u64 pg_div64(__u64 n, __u64 base)
 /*
  * How do we know if the architecture we are running on
  * supports division with 64 bit base?
- * 
+ *
  */
 #if defined(__sparc_v9__) || defined(__powerpc64__) || defined(__alpha__) || defined(__x86_64__) || defined(__ia64__)
 
@@ -467,17 +463,6 @@ static inline __u64 pg_div64(__u64 n, __u64 base)
        return tmp;
 }
 
-static inline u32 pktgen_random(void)
-{
-#if 0
-       __u32 n;
-       get_random_bytes(&n, 4);
-       return n;
-#else
-       return net_random();
-#endif
-}
-
 static inline __u64 getCurMs(void)
 {
        struct timeval tv;
@@ -511,7 +496,7 @@ static void pktgen_stop_all_threads_ifs(void);
 static int pktgen_stop_device(struct pktgen_dev *pkt_dev);
 static void pktgen_stop(struct pktgen_thread *t);
 static void pktgen_clear_counters(struct pktgen_dev *pkt_dev);
-static int pktgen_mark_device(const char *ifname);
+
 static unsigned int scan_ip6(const char *s, char ip[16]);
 static unsigned int fmt_ip6(char *s, const char ip[16]);
 
@@ -529,7 +514,7 @@ static struct notifier_block pktgen_notifier_block = {
 };
 
 /*
- * /proc handling functions 
+ * /proc handling functions
  *
  */
 
@@ -579,7 +564,7 @@ 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 = {
+static const struct file_operations pktgen_fops = {
        .owner   = THIS_MODULE,
        .open    = pgctrl_open,
        .read    = seq_read,
@@ -605,7 +590,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
                   "     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);
+                  pkt_dev->clone_skb, pkt_dev->odev->name);
 
        seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
                   pkt_dev->lflow);
@@ -660,7 +645,7 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->nr_labels) {
                unsigned i;
                seq_printf(seq, "     mpls: ");
-               for(i = 0; i < pkt_dev->nr_labels; i++)
+               for (i = 0; i < pkt_dev->nr_labels; i++)
                        seq_printf(seq, "%08x%s", ntohl(pkt_dev->labels[i]),
                                   i == pkt_dev->nr_labels-1 ? "\n" : ", ");
        }
@@ -765,7 +750,7 @@ static int hex32_arg(const char __user *user_buffer, unsigned long maxlen, __u32
        int i = 0;
        *num = 0;
 
-       for(; i < maxlen; i++) {
+       for (; i < maxlen; i++) {
                char c;
                *num <<= 4;
                if (get_user(c, &user_buffer[i]))
@@ -801,7 +786,7 @@ static int count_trail_chars(const char __user * user_buffer,
                        break;
                default:
                        goto done;
-               };
+               }
        }
 done:
        return i;
@@ -844,7 +829,7 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen)
                        break;
                default:
                        break;
-               };
+               }
        }
 done_str:
        return i;
@@ -873,7 +858,7 @@ static ssize_t get_labels(const char __user *buffer, struct pktgen_dev *pkt_dev)
                n++;
                if (n >= MAX_MPLS_LABELS)
                        return -E2BIG;
-       } while(c == ',');
+       } while (c == ',');
 
        pkt_dev->nr_labels = n;
        return i;
@@ -1502,7 +1487,7 @@ static ssize_t pktgen_if_write(struct file *file,
                if (len < 0) { return len; }
                i += len;
                offset = sprintf(pg_result, "OK: mpls=");
-               for(n = 0; n < pkt_dev->nr_labels; n++)
+               for (n = 0; n < pkt_dev->nr_labels; n++)
                        offset += sprintf(pg_result + offset,
                                          "%08x%s", ntohl(pkt_dev->labels[n]),
                                          n == pkt_dev->nr_labels-1 ? "" : ",");
@@ -1672,7 +1657,7 @@ static int pktgen_if_open(struct inode *inode, struct file *file)
        return single_open(file, pktgen_if_show, PDE(inode)->data);
 }
 
-static struct file_operations pktgen_if_fops = {
+static const struct file_operations pktgen_if_fops = {
        .owner   = THIS_MODULE,
        .open    = pktgen_if_open,
        .read    = seq_read,
@@ -1689,20 +1674,20 @@ static int pktgen_thread_show(struct seq_file *seq, void *v)
        BUG_ON(!t);
 
        seq_printf(seq, "Name: %s  max_before_softirq: %d\n",
-                  t->name, t->max_before_softirq);
+                  t->tsk->comm, t->max_before_softirq);
 
        seq_printf(seq, "Running: ");
 
        if_lock(t);
        list_for_each_entry(pkt_dev, &t->if_list, list)
                if (pkt_dev->running)
-                       seq_printf(seq, "%s ", pkt_dev->ifname);
+                       seq_printf(seq, "%s ", pkt_dev->odev->name);
 
        seq_printf(seq, "\nStopped: ");
 
        list_for_each_entry(pkt_dev, &t->if_list, list)
                if (!pkt_dev->running)
-                       seq_printf(seq, "%s ", pkt_dev->ifname);
+                       seq_printf(seq, "%s ", pkt_dev->odev->name);
 
        if (t->result[0])
                seq_printf(seq, "\nResult: %s\n", t->result);
@@ -1815,7 +1800,7 @@ static int pktgen_thread_open(struct inode *inode, struct file *file)
        return single_open(file, pktgen_thread_show, PDE(inode)->data);
 }
 
-static struct file_operations pktgen_thread_fops = {
+static const struct file_operations pktgen_thread_fops = {
        .owner   = THIS_MODULE,
        .open    = pktgen_thread_open,
        .read    = seq_read,
@@ -1848,16 +1833,14 @@ static struct pktgen_dev *__pktgen_NN_threads(const char *ifname, int remove)
 /*
  * mark a device for removal
  */
-static int pktgen_mark_device(const char *ifname)
+static void pktgen_mark_device(const char *ifname)
 {
        struct pktgen_dev *pkt_dev = NULL;
        const int max_tries = 10, msec_per_try = 125;
        int i = 0;
-       int ret = 0;
 
        mutex_lock(&pktgen_thread_lock);
-       PG_DEBUG(printk("pktgen: pktgen_mark_device marking %s for removal\n",
-                       ifname));
+       pr_debug("pktgen: pktgen_mark_device marking %s for removal\n", ifname);
 
        while (1) {
 
@@ -1866,8 +1849,8 @@ static int pktgen_mark_device(const char *ifname)
                        break;  /* success */
 
                mutex_unlock(&pktgen_thread_lock);
-               PG_DEBUG(printk("pktgen: pktgen_mark_device waiting for %s "
-                               "to disappear....\n", ifname));
+               pr_debug("pktgen: pktgen_mark_device waiting for %s "
+                               "to disappear....\n", ifname);
                schedule_timeout_interruptible(msecs_to_jiffies(msec_per_try));
                mutex_lock(&pktgen_thread_lock);
 
@@ -1875,79 +1858,91 @@ static int pktgen_mark_device(const char *ifname)
                        printk("pktgen_mark_device: timed out after waiting "
                               "%d msec for device %s to be removed\n",
                               msec_per_try * i, ifname);
-                       ret = 1;
                        break;
                }
 
        }
 
        mutex_unlock(&pktgen_thread_lock);
+}
 
-       return ret;
+static void pktgen_change_name(struct net_device *dev)
+{
+       struct pktgen_thread *t;
+
+       list_for_each_entry(t, &pktgen_threads, th_list) {
+               struct pktgen_dev *pkt_dev;
+
+               list_for_each_entry(pkt_dev, &t->if_list, list) {
+                       if (pkt_dev->odev != dev)
+                               continue;
+
+                       remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
+
+                       pkt_dev->entry = create_proc_entry(dev->name, 0600,
+                                                          pg_proc_dir);
+                       if (!pkt_dev->entry)
+                               printk(KERN_ERR "pktgen: can't move proc "
+                                      " entry for '%s'\n", dev->name);
+                       break;
+               }
+       }
 }
 
 static int pktgen_device_event(struct notifier_block *unused,
                               unsigned long event, void *ptr)
 {
-       struct net_device *dev = (struct net_device *)(ptr);
+       struct net_device *dev = ptr;
 
        /* It is OK that we do not hold the group lock right now,
         * as we run under the RTNL lock.
         */
 
        switch (event) {
-       case NETDEV_CHANGEADDR:
-       case NETDEV_GOING_DOWN:
-       case NETDEV_DOWN:
-       case NETDEV_UP:
-               /* Ignore for now */
+       case NETDEV_CHANGENAME:
+               pktgen_change_name(dev);
                break;
 
        case NETDEV_UNREGISTER:
                pktgen_mark_device(dev->name);
                break;
-       };
+       }
 
        return NOTIFY_DONE;
 }
 
 /* Associate pktgen_dev with a device. */
 
-static struct net_device *pktgen_setup_dev(struct pktgen_dev *pkt_dev)
+static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
 {
        struct net_device *odev;
+       int err;
 
        /* Clean old setups */
-
        if (pkt_dev->odev) {
                dev_put(pkt_dev->odev);
                pkt_dev->odev = NULL;
        }
 
-       odev = dev_get_by_name(pkt_dev->ifname);
-
+       odev = dev_get_by_name(ifname);
        if (!odev) {
-               printk("pktgen: no such netdevice: \"%s\"\n", pkt_dev->ifname);
-               goto out;
+               printk("pktgen: no such netdevice: \"%s\"\n", ifname);
+               return -ENODEV;
        }
+
        if (odev->type != ARPHRD_ETHER) {
-               printk("pktgen: not an ethernet device: \"%s\"\n",
-                      pkt_dev->ifname);
-               goto out_put;
-       }
-       if (!netif_running(odev)) {
-               printk("pktgen: device is down: \"%s\"\n", pkt_dev->ifname);
-               goto out_put;
+               printk("pktgen: not an ethernet device: \"%s\"\n", ifname);
+               err = -EINVAL;
+       } else if (!netif_running(odev)) {
+               printk("pktgen: device is down: \"%s\"\n", ifname);
+               err = -ENETDOWN;
+       } else {
+               pkt_dev->odev = odev;
+               return 0;
        }
-       pkt_dev->odev = odev;
 
-       return pkt_dev->odev;
-
-out_put:
        dev_put(odev);
-out:
-       return NULL;
-
+       return err;
 }
 
 /* Read pkt_dev from the interface and set up internal pktgen_dev
@@ -1955,10 +1950,6 @@ out:
  */
 static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
 {
-       /* Try once more, just in case it works now. */
-       if (!pkt_dev->odev)
-               pktgen_setup_dev(pkt_dev);
-
        if (!pkt_dev->odev) {
                printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n");
                sprintf(pkt_dev->result,
@@ -1979,7 +1970,7 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
 
        if (pkt_dev->flags & F_IPV6) {
                /*
-                * Skip this automatic address setting until locks or functions 
+                * Skip this automatic address setting until locks or functions
                 * gets exported
                 */
 
@@ -2095,7 +2086,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
        int flow = 0;
 
        if (pkt_dev->cflows) {
-               flow = pktgen_random() % pkt_dev->cflows;
+               flow = random32() % pkt_dev->cflows;
 
                if (pkt_dev->flows[flow].count > pkt_dev->lflow)
                        pkt_dev->flows[flow].count = 0;
@@ -2107,7 +2098,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                __u32 tmp;
 
                if (pkt_dev->flags & F_MACSRC_RND)
-                       mc = pktgen_random() % (pkt_dev->src_mac_count);
+                       mc = random32() % pkt_dev->src_mac_count;
                else {
                        mc = pkt_dev->cur_src_mac_offset++;
                        if (pkt_dev->cur_src_mac_offset >
@@ -2133,7 +2124,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                __u32 tmp;
 
                if (pkt_dev->flags & F_MACDST_RND)
-                       mc = pktgen_random() % (pkt_dev->dst_mac_count);
+                       mc = random32() % pkt_dev->dst_mac_count;
 
                else {
                        mc = pkt_dev->cur_dst_mac_offset++;
@@ -2157,27 +2148,26 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 
        if (pkt_dev->flags & F_MPLS_RND) {
                unsigned i;
-               for(i = 0; i < pkt_dev->nr_labels; i++)
+               for (i = 0; i < pkt_dev->nr_labels; i++)
                        if (pkt_dev->labels[i] & MPLS_STACK_BOTTOM)
                                pkt_dev->labels[i] = MPLS_STACK_BOTTOM |
-                                            ((__force __be32)pktgen_random() &
+                                            ((__force __be32)random32() &
                                                      htonl(0x000fffff));
        }
 
        if ((pkt_dev->flags & F_VID_RND) && (pkt_dev->vlan_id != 0xffff)) {
-               pkt_dev->vlan_id = pktgen_random() % 4096;
+               pkt_dev->vlan_id = random32() & (4096-1);
        }
 
        if ((pkt_dev->flags & F_SVID_RND) && (pkt_dev->svlan_id != 0xffff)) {
-               pkt_dev->svlan_id = pktgen_random() % 4096;
+               pkt_dev->svlan_id = random32() & (4096 - 1);
        }
 
        if (pkt_dev->udp_src_min < pkt_dev->udp_src_max) {
                if (pkt_dev->flags & F_UDPSRC_RND)
-                       pkt_dev->cur_udp_src =
-                           ((pktgen_random() %
-                             (pkt_dev->udp_src_max - pkt_dev->udp_src_min)) +
-                            pkt_dev->udp_src_min);
+                       pkt_dev->cur_udp_src = random32() %
+                               (pkt_dev->udp_src_max - pkt_dev->udp_src_min)
+                               + pkt_dev->udp_src_min;
 
                else {
                        pkt_dev->cur_udp_src++;
@@ -2188,10 +2178,9 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 
        if (pkt_dev->udp_dst_min < pkt_dev->udp_dst_max) {
                if (pkt_dev->flags & F_UDPDST_RND) {
-                       pkt_dev->cur_udp_dst =
-                           ((pktgen_random() %
-                             (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)) +
-                            pkt_dev->udp_dst_min);
+                       pkt_dev->cur_udp_dst = random32() %
+                               (pkt_dev->udp_dst_max - pkt_dev->udp_dst_min)
+                               + pkt_dev->udp_dst_min;
                } else {
                        pkt_dev->cur_udp_dst++;
                        if (pkt_dev->cur_udp_dst >= pkt_dev->udp_dst_max)
@@ -2206,7 +2195,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                                                               saddr_max))) {
                        __u32 t;
                        if (pkt_dev->flags & F_IPSRC_RND)
-                               t = ((pktgen_random() % (imx - imn)) + imn);
+                               t = random32() % (imx - imn) + imn;
                        else {
                                t = ntohl(pkt_dev->cur_saddr);
                                t++;
@@ -2227,14 +2216,13 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                                __be32 s;
                                if (pkt_dev->flags & F_IPDST_RND) {
 
-                                       t = pktgen_random() % (imx - imn) + imn;
+                                       t = random32() % (imx - imn) + imn;
                                        s = htonl(t);
 
                                        while (LOOPBACK(s) || MULTICAST(s)
                                               || BADCLASS(s) || ZERONET(s)
                                               || LOCAL_MCAST(s)) {
-                                               t = (pktgen_random() %
-                                                     (imx - imn)) + imn;
+                                               t = random32() % (imx - imn) + imn;
                                                s = htonl(t);
                                        }
                                        pkt_dev->cur_daddr = s;
@@ -2266,7 +2254,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 
                        for (i = 0; i < 4; i++) {
                                pkt_dev->cur_in6_daddr.s6_addr32[i] =
-                                   (((__force __be32)pktgen_random() |
+                                   (((__force __be32)random32() |
                                      pkt_dev->min_in6_daddr.s6_addr32[i]) &
                                     pkt_dev->max_in6_daddr.s6_addr32[i]);
                        }
@@ -2276,9 +2264,9 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
        if (pkt_dev->min_pkt_size < pkt_dev->max_pkt_size) {
                __u32 t;
                if (pkt_dev->flags & F_TXSIZE_RND) {
-                       t = ((pktgen_random() %
-                             (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size))
-                            + pkt_dev->min_pkt_size);
+                       t = random32() %
+                               (pkt_dev->max_pkt_size - pkt_dev->min_pkt_size)
+                               + pkt_dev->min_pkt_size;
                } else {
                        t = pkt_dev->cur_pkt_size + 1;
                        if (t > pkt_dev->max_pkt_size)
@@ -2293,7 +2281,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
 {
        unsigned i;
-       for(i = 0; i < pkt_dev->nr_labels; i++) {
+       for (i = 0; i < pkt_dev->nr_labels; i++) {
                *mpls++ = pkt_dev->labels[i] & ~MPLS_STACK_BOTTOM;
        }
        mpls--;
@@ -2315,7 +2303,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        int datalen, iplen;
        struct iphdr *iph;
        struct pktgen_hdr *pgh = NULL;
-       __be16 protocol = __constant_htons(ETH_P_IP);
+       __be16 protocol = htons(ETH_P_IP);
        __be32 *mpls;
        __be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
        __be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
@@ -2324,10 +2312,10 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
 
 
        if (pkt_dev->nr_labels)
-               protocol = __constant_htons(ETH_P_MPLS_UC);
+               protocol = htons(ETH_P_MPLS_UC);
 
        if (pkt_dev->vlan_id != 0xffff)
-               protocol = __constant_htons(ETH_P_8021Q);
+               protocol = htons(ETH_P_8021Q);
 
        /* Update any of the values, used when we're incrementing various
         * fields.
@@ -2353,24 +2341,28 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                mpls_push(mpls, pkt_dev);
 
        if (pkt_dev->vlan_id != 0xffff) {
-               if(pkt_dev->svlan_id != 0xffff) {
+               if (pkt_dev->svlan_id != 0xffff) {
                        svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
                        *svlan_tci = build_tci(pkt_dev->svlan_id,
                                               pkt_dev->svlan_cfi,
                                               pkt_dev->svlan_p);
                        svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
-                       *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q);
+                       *svlan_encapsulated_proto = htons(ETH_P_8021Q);
                }
                vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
                *vlan_tci = build_tci(pkt_dev->vlan_id,
                                      pkt_dev->vlan_cfi,
                                      pkt_dev->vlan_p);
                vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
-               *vlan_encapsulated_proto = __constant_htons(ETH_P_IP);
+               *vlan_encapsulated_proto = htons(ETH_P_IP);
        }
 
-       iph = (struct iphdr *)skb_put(skb, sizeof(struct iphdr));
-       udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
+       skb->network_header = skb->tail;
+       skb->transport_header = skb->network_header + sizeof(struct iphdr);
+       skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
+
+       iph = ip_hdr(skb);
+       udph = udp_hdr(skb);
 
        memcpy(eth, pkt_dev->hh, 12);
        *(__be16 *) & eth[12] = protocol;
@@ -2399,12 +2391,11 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        iph->check = 0;
        iph->check = ip_fast_csum((void *)iph, iph->ihl);
        skb->protocol = protocol;
-       skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) -
-               VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+       skb->mac_header = (skb->network_header - ETH_HLEN -
+                          pkt_dev->nr_labels * sizeof(u32) -
+                          VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev));
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
-       skb->nh.iph = iph;
-       skb->h.uh = udph;
 
        if (pkt_dev->nfrags <= 0)
                pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
@@ -2477,10 +2468,10 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
 }
 
 /*
- * scan_ip6, fmt_ip taken from dietlibc-0.21 
+ * scan_ip6, fmt_ip taken from dietlibc-0.21
  * Author Felix von Leitner <felix-dietlibc@fefe.de>
  *
- * Slightly modified for kernel. 
+ * Slightly modified for kernel.
  * Should be candidate for net/ipv4/utils.c
  * --ro
  */
@@ -2653,7 +2644,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        int datalen;
        struct ipv6hdr *iph;
        struct pktgen_hdr *pgh = NULL;
-       __be16 protocol = __constant_htons(ETH_P_IPV6);
+       __be16 protocol = htons(ETH_P_IPV6);
        __be32 *mpls;
        __be16 *vlan_tci = NULL;                 /* Encapsulates priority and VLAN ID */
        __be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
@@ -2661,10 +2652,10 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
 
        if (pkt_dev->nr_labels)
-               protocol = __constant_htons(ETH_P_MPLS_UC);
+               protocol = htons(ETH_P_MPLS_UC);
 
        if (pkt_dev->vlan_id != 0xffff)
-               protocol = __constant_htons(ETH_P_8021Q);
+               protocol = htons(ETH_P_8021Q);
 
        /* Update any of the values, used when we're incrementing various
         * fields.
@@ -2689,24 +2680,28 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
                mpls_push(mpls, pkt_dev);
 
        if (pkt_dev->vlan_id != 0xffff) {
-               if(pkt_dev->svlan_id != 0xffff) {
+               if (pkt_dev->svlan_id != 0xffff) {
                        svlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
                        *svlan_tci = build_tci(pkt_dev->svlan_id,
                                               pkt_dev->svlan_cfi,
                                               pkt_dev->svlan_p);
                        svlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
-                       *svlan_encapsulated_proto = __constant_htons(ETH_P_8021Q);
+                       *svlan_encapsulated_proto = htons(ETH_P_8021Q);
                }
                vlan_tci = (__be16 *)skb_put(skb, sizeof(__be16));
                *vlan_tci = build_tci(pkt_dev->vlan_id,
                                      pkt_dev->vlan_cfi,
                                      pkt_dev->vlan_p);
                vlan_encapsulated_proto = (__be16 *)skb_put(skb, sizeof(__be16));
-               *vlan_encapsulated_proto = __constant_htons(ETH_P_IPV6);
+               *vlan_encapsulated_proto = htons(ETH_P_IPV6);
        }
 
-       iph = (struct ipv6hdr *)skb_put(skb, sizeof(struct ipv6hdr));
-       udph = (struct udphdr *)skb_put(skb, sizeof(struct udphdr));
+       skb->network_header = skb->tail;
+       skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
+       skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
+
+       iph = ipv6_hdr(skb);
+       udph = udp_hdr(skb);
 
        memcpy(eth, pkt_dev->hh, 12);
        *(__be16 *) & eth[12] = protocol;
@@ -2728,7 +2723,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        udph->len = htons(datalen + sizeof(struct udphdr));
        udph->check = 0;        /* No checksum */
 
-       *(__be32 *) iph = __constant_htonl(0x60000000); /* Version + flow */
+       *(__be32 *) iph = htonl(0x60000000);    /* Version + flow */
 
        if (pkt_dev->traffic_class) {
                /* Version + traffic class + flow (0) */
@@ -2743,13 +2738,12 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        ipv6_addr_copy(&iph->daddr, &pkt_dev->cur_in6_daddr);
        ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
 
-       skb->mac.raw = ((u8 *) iph) - 14 - pkt_dev->nr_labels*sizeof(u32) -
-               VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+       skb->mac_header = (skb->network_header - ETH_HLEN -
+                          pkt_dev->nr_labels * sizeof(u32) -
+                          VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev));
        skb->protocol = protocol;
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
-       skb->nh.ipv6h = iph;
-       skb->h.uh = udph;
 
        if (pkt_dev->nfrags <= 0)
                pgh = (struct pktgen_hdr *)skb_put(skb, datalen);
@@ -2847,7 +2841,7 @@ static void pktgen_run(struct pktgen_thread *t)
        struct pktgen_dev *pkt_dev;
        int started = 0;
 
-       PG_DEBUG(printk("pktgen: entering pktgen_run. %p\n", t));
+       pr_debug("pktgen: entering pktgen_run. %p\n", t);
 
        if_lock(t);
        list_for_each_entry(pkt_dev, &t->if_list, list) {
@@ -2879,7 +2873,7 @@ static void pktgen_stop_all_threads_ifs(void)
 {
        struct pktgen_thread *t;
 
-       PG_DEBUG(printk("pktgen: entering pktgen_stop_all_threads_ifs.\n"));
+       pr_debug("pktgen: entering pktgen_stop_all_threads_ifs.\n");
 
        mutex_lock(&pktgen_thread_lock);
 
@@ -2947,7 +2941,7 @@ static void pktgen_run_all_threads(void)
 {
        struct pktgen_thread *t;
 
-       PG_DEBUG(printk("pktgen: entering pktgen_run_all_threads.\n"));
+       pr_debug("pktgen: entering pktgen_run_all_threads.\n");
 
        mutex_lock(&pktgen_thread_lock);
 
@@ -3005,7 +2999,7 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
 
        if (!pkt_dev->running) {
                printk("pktgen: interface: %s is already stopped\n",
-                      pkt_dev->ifname);
+                      pkt_dev->odev->name);
                return -EINVAL;
        }
 
@@ -3039,7 +3033,7 @@ static void pktgen_stop(struct pktgen_thread *t)
 {
        struct pktgen_dev *pkt_dev;
 
-       PG_DEBUG(printk("pktgen: entering pktgen_stop\n"));
+       pr_debug("pktgen: entering pktgen_stop\n");
 
        if_lock(t);
 
@@ -3063,7 +3057,7 @@ static void pktgen_rem_one_if(struct pktgen_thread *t)
        struct list_head *q, *n;
        struct pktgen_dev *cur;
 
-       PG_DEBUG(printk("pktgen: entering pktgen_rem_one_if\n"));
+       pr_debug("pktgen: entering pktgen_rem_one_if\n");
 
        if_lock(t);
 
@@ -3092,7 +3086,7 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t)
 
        /* Remove all devices, free mem */
 
-       PG_DEBUG(printk("pktgen: entering pktgen_rem_all_ifs\n"));
+       pr_debug("pktgen: entering pktgen_rem_all_ifs\n");
        if_lock(t);
 
        list_for_each_safe(q, n, &t->if_list) {
@@ -3112,7 +3106,7 @@ static void pktgen_rem_thread(struct pktgen_thread *t)
 {
        /* Remove from the thread list */
 
-       remove_proc_entry(t->name, pg_proc_dir);
+       remove_proc_entry(t->tsk->comm, pg_proc_dir);
 
        mutex_lock(&pktgen_thread_lock);
 
@@ -3256,62 +3250,44 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 out:;
 }
 
-/* 
+/*
  * Main loop of the thread goes here
  */
 
-static void pktgen_thread_worker(struct pktgen_thread *t)
+static int pktgen_thread_worker(void *arg)
 {
        DEFINE_WAIT(wait);
+       struct pktgen_thread *t = arg;
        struct pktgen_dev *pkt_dev = NULL;
        int cpu = t->cpu;
-       sigset_t tmpsig;
        u32 max_before_softirq;
        u32 tx_since_softirq = 0;
 
-       daemonize("pktgen/%d", cpu);
-
-       /* Block all signals except SIGKILL, SIGSTOP and SIGTERM */
-
-       spin_lock_irq(&current->sighand->siglock);
-       tmpsig = current->blocked;
-       siginitsetinv(&current->blocked,
-                     sigmask(SIGKILL) | sigmask(SIGSTOP) | sigmask(SIGTERM));
-
-       recalc_sigpending();
-       spin_unlock_irq(&current->sighand->siglock);
-
-       /* Migrate to the right CPU */
-       set_cpus_allowed(current, cpumask_of_cpu(cpu));
-       if (smp_processor_id() != cpu)
-               BUG();
+       BUG_ON(smp_processor_id() != cpu);
 
        init_waitqueue_head(&t->queue);
 
-       t->control &= ~(T_TERMINATE);
-       t->control &= ~(T_RUN);
-       t->control &= ~(T_STOP);
-       t->control &= ~(T_REMDEVALL);
-       t->control &= ~(T_REMDEV);
-
        t->pid = current->pid;
 
-       PG_DEBUG(printk("pktgen: starting pktgen/%d:  pid=%d\n", cpu, current->pid));
+       pr_debug("pktgen: starting pktgen/%d:  pid=%d\n", cpu, current->pid);
 
        max_before_softirq = t->max_before_softirq;
 
-       __set_current_state(TASK_INTERRUPTIBLE);
-       mb();
-
-       while (1) {
+       set_current_state(TASK_INTERRUPTIBLE);
 
-               __set_current_state(TASK_RUNNING);
+       while (!kthread_should_stop()) {
+               pkt_dev = next_to_run(t);
 
-               /*
-                * Get next dev to xmit -- if any.
-                */
+               if (!pkt_dev &&
+                   (t->control & (T_STOP | T_RUN | T_REMDEVALL | T_REMDEV))
+                   == 0) {
+                       prepare_to_wait(&(t->queue), &wait,
+                                       TASK_INTERRUPTIBLE);
+                       schedule_timeout(HZ / 10);
+                       finish_wait(&(t->queue), &wait);
+               }
 
-               pkt_dev = next_to_run(t);
+               __set_current_state(TASK_RUNNING);
 
                if (pkt_dev) {
 
@@ -3329,21 +3305,8 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
                                        do_softirq();
                                tx_since_softirq = 0;
                        }
-               } else {
-                       prepare_to_wait(&(t->queue), &wait, TASK_INTERRUPTIBLE);
-                       schedule_timeout(HZ / 10);
-                       finish_wait(&(t->queue), &wait);
                }
 
-               /*
-                * Back from sleep, either due to the timeout or signal.
-                * We check if we have any "posted" work for us.
-                */
-
-               if (t->control & T_TERMINATE || signal_pending(current))
-                       /* we received a request to terminate ourself */
-                       break;
-
                if (t->control & T_STOP) {
                        pktgen_stop(t);
                        t->control &= ~(T_STOP);
@@ -3364,20 +3327,21 @@ static void pktgen_thread_worker(struct pktgen_thread *t)
                        t->control &= ~(T_REMDEV);
                }
 
-               if (need_resched())
-                       schedule();
+               try_to_freeze();
+
+               set_current_state(TASK_INTERRUPTIBLE);
        }
 
-       PG_DEBUG(printk("pktgen: %s stopping all device\n", t->name));
+       pr_debug("pktgen: %s stopping all device\n", t->tsk->comm);
        pktgen_stop(t);
 
-       PG_DEBUG(printk("pktgen: %s removing all device\n", t->name));
+       pr_debug("pktgen: %s removing all device\n", t->tsk->comm);
        pktgen_rem_all_ifs(t);
 
-       PG_DEBUG(printk("pktgen: %s removing thread.\n", t->name));
+       pr_debug("pktgen: %s removing thread.\n", t->tsk->comm);
        pktgen_rem_thread(t);
 
-       t->removed = 1;
+       return 0;
 }
 
 static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
@@ -3387,18 +3351,18 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
        if_lock(t);
 
        list_for_each_entry(p, &t->if_list, list)
-               if (strncmp(p->ifname, ifname, IFNAMSIZ) == 0) {
+               if (strncmp(p->odev->name, ifname, IFNAMSIZ) == 0) {
                        pkt_dev = p;
                        break;
                }
 
        if_unlock(t);
-       PG_DEBUG(printk("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev));
+       pr_debug("pktgen: find_dev(%s) returning %p\n", ifname, pkt_dev);
        return pkt_dev;
 }
 
-/* 
- * Adds a dev at front of if_list. 
+/*
+ * Adds a dev at front of if_list.
  */
 
 static int add_dev_to_thread(struct pktgen_thread *t,
@@ -3428,7 +3392,7 @@ out:
 static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 {
        struct pktgen_dev *pkt_dev;
-       struct proc_dir_entry *pe;
+       int err;
 
        /* We don't allow a device to be on several threads */
 
@@ -3470,62 +3434,35 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
        pkt_dev->svlan_cfi = 0;
        pkt_dev->svlan_id = 0xffff;
 
-       strncpy(pkt_dev->ifname, ifname, IFNAMSIZ);
-
-       if (!pktgen_setup_dev(pkt_dev)) {
-               printk("pktgen: ERROR: pktgen_setup_dev failed.\n");
-               if (pkt_dev->flows)
-                       vfree(pkt_dev->flows);
-               kfree(pkt_dev);
-               return -ENODEV;
-       }
+       err = pktgen_setup_dev(pkt_dev, ifname);
+       if (err)
+               goto out1;
 
-       pe = create_proc_entry(ifname, 0600, pg_proc_dir);
-       if (!pe) {
+       pkt_dev->entry = create_proc_entry(ifname, 0600, pg_proc_dir);
+       if (!pkt_dev->entry) {
                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;
+               err = -EINVAL;
+               goto out2;
        }
-       pe->proc_fops = &pktgen_if_fops;
-       pe->data = pkt_dev;
+       pkt_dev->entry->proc_fops = &pktgen_if_fops;
+       pkt_dev->entry->data = pkt_dev;
 
        return add_dev_to_thread(t, pkt_dev);
+out2:
+       dev_put(pkt_dev->odev);
+out1:
+       if (pkt_dev->flows)
+               vfree(pkt_dev->flows);
+       kfree(pkt_dev);
+       return err;
 }
 
-static struct pktgen_thread *__init pktgen_find_thread(const char *name)
+static int __init pktgen_create_thread(int cpu)
 {
        struct pktgen_thread *t;
-
-       mutex_lock(&pktgen_thread_lock);
-
-       list_for_each_entry(t, &pktgen_threads, th_list)
-               if (strcmp(t->name, name) == 0) {
-                       mutex_unlock(&pktgen_thread_lock);
-                       return t;
-               }
-
-       mutex_unlock(&pktgen_thread_lock);
-       return NULL;
-}
-
-static int __init pktgen_create_thread(const char *name, int cpu)
-{
-       int err;
-       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");
-               return -EINVAL;
-       }
-
-       if (pktgen_find_thread(name)) {
-               printk("pktgen: ERROR: thread: %s already exists\n", name);
-               return -EINVAL;
-       }
+       struct task_struct *p;
 
        t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
        if (!t) {
@@ -3533,14 +3470,29 @@ static int __init pktgen_create_thread(const char *name, int cpu)
                return -ENOMEM;
        }
 
-       strcpy(t->name, name);
        spin_lock_init(&t->if_lock);
        t->cpu = cpu;
 
-       pe = create_proc_entry(t->name, 0600, pg_proc_dir);
+       INIT_LIST_HEAD(&t->if_list);
+
+       list_add_tail(&t->th_list, &pktgen_threads);
+
+       p = kthread_create(pktgen_thread_worker, t, "kpktgend_%d", cpu);
+       if (IS_ERR(p)) {
+               printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
+               list_del(&t->th_list);
+               kfree(t);
+               return PTR_ERR(p);
+       }
+       kthread_bind(p, cpu);
+       t->tsk = p;
+
+       pe = create_proc_entry(t->tsk->comm, 0600, pg_proc_dir);
        if (!pe) {
                printk("pktgen: cannot create %s/%s procfs entry.\n",
-                      PG_PROC_DIR, t->name);
+                      PG_PROC_DIR, t->tsk->comm);
+               kthread_stop(p);
+               list_del(&t->th_list);
                kfree(t);
                return -EINVAL;
        }
@@ -3548,27 +3500,13 @@ static int __init pktgen_create_thread(const char *name, int cpu)
        pe->proc_fops = &pktgen_thread_fops;
        pe->data = t;
 
-       INIT_LIST_HEAD(&t->if_list);
-
-       list_add_tail(&t->th_list, &pktgen_threads);
-
-       t->removed = 0;
-
-       err = kernel_thread((void *)pktgen_thread_worker, (void *)t,
-                         CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
-       if (err < 0) {
-               printk("pktgen: kernel_thread() failed for cpu %d\n", t->cpu);
-               remove_proc_entry(t->name, pg_proc_dir);
-               list_del(&t->th_list);
-               kfree(t);
-               return err;
-       }
+       wake_up_process(p);
 
        return 0;
 }
 
-/* 
- * Removes a device from the thread if_list. 
+/*
+ * Removes a device from the thread if_list.
  */
 static void _rem_dev_from_if_list(struct pktgen_thread *t,
                                  struct pktgen_dev *pkt_dev)
@@ -3587,7 +3525,7 @@ static int pktgen_remove_device(struct pktgen_thread *t,
                                struct pktgen_dev *pkt_dev)
 {
 
-       PG_DEBUG(printk("pktgen: remove_device pkt_dev=%p\n", pkt_dev));
+       pr_debug("pktgen: remove_device pkt_dev=%p\n", pkt_dev);
 
        if (pkt_dev->running) {
                printk("pktgen:WARNING: trying to remove a running interface, stopping it now.\n");
@@ -3605,9 +3543,8 @@ static int pktgen_remove_device(struct pktgen_thread *t,
 
        _rem_dev_from_if_list(t, pkt_dev);
 
-       /* Clean up proc file system */
-
-       remove_proc_entry(pkt_dev->ifname, pg_proc_dir);
+       if (pkt_dev->entry)
+               remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
 
        if (pkt_dev->flows)
                vfree(pkt_dev->flows);
@@ -3643,10 +3580,8 @@ static int __init pg_init(void)
 
        for_each_online_cpu(cpu) {
                int err;
-               char buf[30];
 
-               sprintf(buf, "kpktgend_%i", cpu);
-               err = pktgen_create_thread(buf, cpu);
+               err = pktgen_create_thread(cpu);
                if (err)
                        printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n",
                                        cpu, err);
@@ -3674,9 +3609,8 @@ static void __exit pg_cleanup(void)
 
        list_for_each_safe(q, n, &pktgen_threads) {
                t = list_entry(q, struct pktgen_thread, th_list);
-               t->control |= (T_TERMINATE);
-
-               wait_event_interruptible_timeout(queue, (t->removed == 1), HZ);
+               kthread_stop(t->tsk);
+               kfree(t);
        }
 
        /* Un-register us from receiving netdevice events */