Freezer: make kernel threads nonfreezable by default
[safe/jmp/linux-2.6] / net / core / pktgen.c
index 04d4b93..bca787f 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/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
-#include <linux/smp_lock.h>
 #include <linux/mutex.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #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 <net/checksum.h>
 #include <net/ipv6.h>
 #include <net/addrconf.h>
+#ifdef CONFIG_XFRM
+#include <net/xfrm.h>
+#endif
 #include <asm/byteorder.h>
 #include <linux/rcupdate.h>
 #include <asm/bitops.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  */
 #define F_MPLS_RND    (1<<8)   /* Random MPLS labels */
 #define F_VID_RND     (1<<9)   /* Random VLAN ID */
 #define F_SVID_RND    (1<<10)  /* Random SVLAN ID */
+#define F_FLOW_SEQ    (1<<11)  /* Sequential flows */
+#define F_IPSEC_ON    (1<<12)  /* ipsec on for flows */
 
 /* Thread control flag bits */
 #define T_TERMINATE   (1<<0)
@@ -210,18 +212,21 @@ static struct proc_dir_entry *pg_proc_dir = NULL;
 struct flow_state {
        __be32 cur_daddr;
        int count;
+#ifdef CONFIG_XFRM
+       struct xfrm_state *x;
+#endif
+       __u32 flags;
 };
 
-struct pktgen_dev {
+/* flow flag bits */
+#define F_INIT   (1<<0)                /* flow has been initialized */
 
+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 */
@@ -235,6 +240,7 @@ struct pktgen_dev {
 
        int min_pkt_size;       /* = ETH_ZLEN; */
        int max_pkt_size;       /* = ETH_ZLEN; */
+       int pkt_overhead;       /* overhead for MPLS, VLANs, IPSEC etc */
        int nfrags;
        __u32 delay_us;         /* Default delay */
        __u32 delay_ns;
@@ -348,6 +354,12 @@ struct pktgen_dev {
        unsigned cflows;        /* Concurrent flows (config) */
        unsigned lflow;         /* Flow length  (config) */
        unsigned nflows;        /* accumulated flows (stats) */
+       unsigned curfl;         /* current sequenced flow (state)*/
+#ifdef CONFIG_XFRM
+       __u8    ipsmode;                /* IPSEC mode (config) */
+       __u8    ipsproto;               /* IPSEC type (config) */
+#endif
+       char result[512];
 };
 
 struct pktgen_hdr {
@@ -456,7 +468,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 +479,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 +512,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 +530,7 @@ static struct notifier_block pktgen_notifier_block = {
 };
 
 /*
- * /proc handling functions 
+ * /proc handling functions
  *
  */
 
@@ -579,7 +580,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 +606,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 +661,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" : ", ");
        }
@@ -706,6 +707,18 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->flags & F_MPLS_RND)
                seq_printf(seq,  "MPLS_RND  ");
 
+       if (pkt_dev->cflows) {
+               if (pkt_dev->flags & F_FLOW_SEQ)
+                       seq_printf(seq,  "FLOW_SEQ  "); /*in sequence flows*/
+               else
+                       seq_printf(seq,  "FLOW_RND  ");
+       }
+
+#ifdef CONFIG_XFRM
+       if (pkt_dev->flags & F_IPSEC_ON)
+               seq_printf(seq,  "IPSEC  ");
+#endif
+
        if (pkt_dev->flags & F_MACSRC_RND)
                seq_printf(seq, "MACSRC_RND  ");
 
@@ -765,7 +778,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 +814,7 @@ static int count_trail_chars(const char __user * user_buffer,
                        break;
                default:
                        goto done;
-               };
+               }
        }
 done:
        return i;
@@ -844,7 +857,7 @@ static int strn_len(const char __user * user_buffer, unsigned int maxlen)
                        break;
                default:
                        break;
-               };
+               }
        }
 done_str:
        return i;
@@ -873,7 +886,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;
@@ -1197,6 +1210,14 @@ static ssize_t pktgen_if_write(struct file *file,
                else if (strcmp(f, "!SVID_RND") == 0)
                        pkt_dev->flags &= ~F_SVID_RND;
 
+               else if (strcmp(f, "FLOW_SEQ") == 0)
+                       pkt_dev->flags |= F_FLOW_SEQ;
+
+#ifdef CONFIG_XFRM
+               else if (strcmp(f, "IPSEC") == 0)
+                       pkt_dev->flags |= F_IPSEC_ON;
+#endif
+
                else if (strcmp(f, "!IPV6") == 0)
                        pkt_dev->flags &= ~F_IPV6;
 
@@ -1205,7 +1226,7 @@ static ssize_t pktgen_if_write(struct file *file,
                                "Flag -:%s:- unknown\nAvailable flags, (prepend ! to un-set flag):\n%s",
                                f,
                                "IPSRC_RND, IPDST_RND, UDPSRC_RND, UDPDST_RND, "
-                               "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND\n");
+                               "MACSRC_RND, MACDST_RND, TXSIZE_RND, IPV6, MPLS_RND, VID_RND, SVID_RND, FLOW_SEQ, IPSEC\n");
                        return count;
                }
                sprintf(pg_result, "OK: flags=0x%x", pkt_dev->flags);
@@ -1502,7 +1523,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 +1693,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,
@@ -1696,13 +1717,13 @@ static int pktgen_thread_show(struct seq_file *seq, void *v)
        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 +1836,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 +1869,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 +1885,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 +1894,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 +1986,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 +2006,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
                 */
 
@@ -2085,6 +2112,70 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
        pkt_dev->idle_acc += now - start;
 }
 
+static inline void set_pkt_overhead(struct pktgen_dev *pkt_dev)
+{
+       pkt_dev->pkt_overhead = 0;
+       pkt_dev->pkt_overhead += pkt_dev->nr_labels*sizeof(u32);
+       pkt_dev->pkt_overhead += VLAN_TAG_SIZE(pkt_dev);
+       pkt_dev->pkt_overhead += SVLAN_TAG_SIZE(pkt_dev);
+}
+
+static inline int f_seen(struct pktgen_dev *pkt_dev, int flow)
+{
+
+       if (pkt_dev->flows[flow].flags & F_INIT)
+               return 1;
+       else
+               return 0;
+}
+
+static inline int f_pick(struct pktgen_dev *pkt_dev)
+{
+       int flow = pkt_dev->curfl;
+
+       if (pkt_dev->flags & F_FLOW_SEQ) {
+               if (pkt_dev->flows[flow].count >= pkt_dev->lflow) {
+                       /* reset time */
+                       pkt_dev->flows[flow].count = 0;
+                       pkt_dev->curfl += 1;
+                       if (pkt_dev->curfl >= pkt_dev->cflows)
+                               pkt_dev->curfl = 0; /*reset */
+               }
+       } else {
+               flow = random32() % pkt_dev->cflows;
+
+               if (pkt_dev->flows[flow].count > pkt_dev->lflow)
+                       pkt_dev->flows[flow].count = 0;
+       }
+
+       return pkt_dev->curfl;
+}
+
+
+#ifdef CONFIG_XFRM
+/* If there was already an IPSEC SA, we keep it as is, else
+ * we go look for it ...
+*/
+inline
+void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
+{
+       struct xfrm_state *x = pkt_dev->flows[flow].x;
+       if (!x) {
+               /*slow path: we dont already have xfrm_state*/
+               x = xfrm_stateonly_find((xfrm_address_t *)&pkt_dev->cur_daddr,
+                                       (xfrm_address_t *)&pkt_dev->cur_saddr,
+                                       AF_INET,
+                                       pkt_dev->ipsmode,
+                                       pkt_dev->ipsproto, 0);
+               if (x) {
+                       pkt_dev->flows[flow].x = x;
+                       set_pkt_overhead(pkt_dev);
+                       pkt_dev->pkt_overhead+=x->props.header_len;
+               }
+
+       }
+}
+#endif
 /* Increment/randomize headers according to flags and current values
  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
  */
@@ -2094,12 +2185,8 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
        __u32 imx;
        int flow = 0;
 
-       if (pkt_dev->cflows) {
-               flow = pktgen_random() % pkt_dev->cflows;
-
-               if (pkt_dev->flows[flow].count > pkt_dev->lflow)
-                       pkt_dev->flows[flow].count = 0;
-       }
+       if (pkt_dev->cflows)
+               flow = f_pick(pkt_dev);
 
        /*  Deal with source MAC */
        if (pkt_dev->src_mac_count > 1) {
@@ -2107,7 +2194,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 +2220,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 +2244,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 +2274,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 +2291,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++;
@@ -2217,7 +2302,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                        pkt_dev->cur_saddr = htonl(t);
                }
 
-               if (pkt_dev->cflows && pkt_dev->flows[flow].count != 0) {
+               if (pkt_dev->cflows && f_seen(pkt_dev, flow)) {
                        pkt_dev->cur_daddr = pkt_dev->flows[flow].cur_daddr;
                } else {
                        imn = ntohl(pkt_dev->daddr_min);
@@ -2227,14 +2312,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;
@@ -2248,8 +2332,13 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                                }
                        }
                        if (pkt_dev->cflows) {
+                               pkt_dev->flows[flow].flags |= F_INIT;
                                pkt_dev->flows[flow].cur_daddr =
                                    pkt_dev->cur_daddr;
+#ifdef CONFIG_XFRM
+                               if (pkt_dev->flags & F_IPSEC_ON)
+                                       get_ipsec_sa(pkt_dev, flow);
+#endif
                                pkt_dev->nflows++;
                        }
                }
@@ -2266,7 +2355,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 +2365,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)
@@ -2290,10 +2379,95 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
        pkt_dev->flows[flow].count++;
 }
 
+
+#ifdef CONFIG_XFRM
+static int pktgen_output_ipsec(struct sk_buff *skb, struct pktgen_dev *pkt_dev)
+{
+       struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
+       int err = 0;
+       struct iphdr *iph;
+
+       if (!x)
+               return 0;
+       /* XXX: we dont support tunnel mode for now until
+        * we resolve the dst issue */
+       if (x->props.mode != XFRM_MODE_TRANSPORT)
+               return 0;
+
+       spin_lock(&x->lock);
+       iph = ip_hdr(skb);
+
+       err = x->mode->output(x, skb);
+       if (err)
+               goto error;
+       err = x->type->output(x, skb);
+       if (err)
+               goto error;
+
+       x->curlft.bytes +=skb->len;
+       x->curlft.packets++;
+       spin_unlock(&x->lock);
+
+error:
+       spin_unlock(&x->lock);
+       return err;
+}
+
+static inline void free_SAs(struct pktgen_dev *pkt_dev)
+{
+       if (pkt_dev->cflows) {
+               /* let go of the SAs if we have them */
+               int i = 0;
+               for (;  i < pkt_dev->nflows; i++){
+                       struct xfrm_state *x = pkt_dev->flows[i].x;
+                       if (x) {
+                               xfrm_state_put(x);
+                               pkt_dev->flows[i].x = NULL;
+                       }
+               }
+       }
+}
+
+static inline int process_ipsec(struct pktgen_dev *pkt_dev,
+                             struct sk_buff *skb, __be16 protocol)
+{
+       if (pkt_dev->flags & F_IPSEC_ON) {
+               struct xfrm_state *x = pkt_dev->flows[pkt_dev->curfl].x;
+               int nhead = 0;
+               if (x) {
+                       int ret;
+                       __u8 *eth;
+                       nhead = x->props.header_len - skb_headroom(skb);
+                       if (nhead >0) {
+                               ret = pskb_expand_head(skb, nhead, 0, GFP_ATOMIC);
+                               if (ret < 0) {
+                                       printk("Error expanding ipsec packet %d\n",ret);
+                                       return 0;
+                               }
+                       }
+
+                       /* ipsec is not expecting ll header */
+                       skb_pull(skb, ETH_HLEN);
+                       ret = pktgen_output_ipsec(skb, pkt_dev);
+                       if (ret) {
+                               printk("Error creating ipsec packet %d\n",ret);
+                               kfree_skb(skb);
+                               return 0;
+                       }
+                       /* restore ll */
+                       eth = (__u8 *) skb_push(skb, ETH_HLEN);
+                       memcpy(eth, pkt_dev->hh, 12);
+                       *(u16 *) & eth[12] = protocol;
+               }
+       }
+       return 1;
+}
+#endif
+
 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 +2489,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 +2498,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.
@@ -2336,9 +2510,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
 
        datalen = (odev->hard_header_len + 16) & ~0xf;
        skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + datalen +
-                       pkt_dev->nr_labels*sizeof(u32) +
-                       VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev),
-                       GFP_ATOMIC);
+                       pkt_dev->pkt_overhead, GFP_ATOMIC);
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
                return NULL;
@@ -2353,31 +2525,35 @@ 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;
 
        /* Eth + IPh + UDPh + mpls */
        datalen = pkt_dev->cur_pkt_size - 14 - 20 - 8 -
-                 pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+                 pkt_dev->pkt_overhead;
        if (datalen < sizeof(struct pktgen_hdr))
                datalen = sizeof(struct pktgen_hdr);
 
@@ -2399,12 +2575,10 @@ 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->pkt_overhead);
        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);
@@ -2473,14 +2647,19 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
                pgh->tv_usec = htonl(timestamp.tv_usec);
        }
 
+#ifdef CONFIG_XFRM
+       if (!process_ipsec(pkt_dev, skb, protocol))
+               return NULL;
+#endif
+
        return skb;
 }
 
 /*
- * 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 +2832,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 +2840,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.
@@ -2672,9 +2851,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        mod_cur_headers(pkt_dev);
 
        skb = alloc_skb(pkt_dev->cur_pkt_size + 64 + 16 +
-                       pkt_dev->nr_labels*sizeof(u32) +
-                       VLAN_TAG_SIZE(pkt_dev) + SVLAN_TAG_SIZE(pkt_dev),
-                       GFP_ATOMIC);
+                       pkt_dev->pkt_overhead, GFP_ATOMIC);
        if (!skb) {
                sprintf(pkt_dev->result, "No memory");
                return NULL;
@@ -2689,24 +2866,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;
@@ -2714,7 +2895,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        /* Eth + IPh + UDPh + mpls */
        datalen = pkt_dev->cur_pkt_size - 14 -
                  sizeof(struct ipv6hdr) - sizeof(struct udphdr) -
-                 pkt_dev->nr_labels*sizeof(u32) - VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev);
+                 pkt_dev->pkt_overhead;
 
        if (datalen < sizeof(struct pktgen_hdr)) {
                datalen = sizeof(struct pktgen_hdr);
@@ -2728,7 +2909,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 +2924,11 @@ 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->pkt_overhead);
        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 +3026,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) {
@@ -2864,6 +3043,7 @@ static void pktgen_run(struct pktgen_thread *t)
                        pkt_dev->started_at = getCurUs();
                        pkt_dev->next_tx_us = getCurUs();       /* Transmit immediately */
                        pkt_dev->next_tx_ns = 0;
+                       set_pkt_overhead(pkt_dev);
 
                        strcpy(pkt_dev->result, "Starting");
                        started++;
@@ -2879,7 +3059,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 +3127,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 +3185,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 +3219,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 +3243,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 +3272,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) {
@@ -3146,7 +3326,9 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                }
        }
 
-       if (netif_queue_stopped(odev) || need_resched()) {
+       if ((netif_queue_stopped(odev) ||
+            netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) ||
+            need_resched()) {
                idle_start = getCurUs();
 
                if (!netif_running(odev)) {
@@ -3161,7 +3343,8 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
                pkt_dev->idle_acc += getCurUs() - idle_start;
 
-               if (netif_queue_stopped(odev)) {
+               if (netif_queue_stopped(odev) ||
+                   netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
                        pkt_dev->next_tx_us = getCurUs();       /* TODO */
                        pkt_dev->next_tx_ns = 0;
                        goto out;       /* Try the next interface */
@@ -3188,7 +3371,8 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
        }
 
        netif_tx_lock_bh(odev);
-       if (!netif_queue_stopped(odev)) {
+       if (!netif_queue_stopped(odev) &&
+           !netif_subqueue_stopped(odev, pkt_dev->skb->queue_mapping)) {
 
                atomic_inc(&(pkt_dev->skb->users));
              retry_now:
@@ -3256,7 +3440,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 out:;
 }
 
-/* 
+/*
  * Main loop of the thread goes here
  */
 
@@ -3275,12 +3459,14 @@ static int pktgen_thread_worker(void *arg)
 
        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);
 
+       set_freezable();
+
        while (!kthread_should_stop()) {
                pkt_dev = next_to_run(t);
 
@@ -3333,16 +3519,18 @@ static int pktgen_thread_worker(void *arg)
                        t->control &= ~(T_REMDEV);
                }
 
+               try_to_freeze();
+
                set_current_state(TASK_INTERRUPTIBLE);
        }
 
-       PG_DEBUG(printk("pktgen: %s stopping all device\n", t->tsk->comm));
+       pr_debug("pktgen: %s stopping all device\n", t->tsk->comm);
        pktgen_stop(t);
 
-       PG_DEBUG(printk("pktgen: %s removing all device\n", t->tsk->comm));
+       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->tsk->comm));
+       pr_debug("pktgen: %s removing thread.\n", t->tsk->comm);
        pktgen_rem_thread(t);
 
        return 0;
@@ -3355,18 +3543,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,
@@ -3396,7 +3584,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 */
 
@@ -3438,29 +3626,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);
+       err = pktgen_setup_dev(pkt_dev, ifname);
+       if (err)
+               goto out1;
 
-       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;
-       }
-
-       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;
-       }
-       pe->proc_fops = &pktgen_if_fops;
-       pe->data = pkt_dev;
+               err = -EINVAL;
+               goto out2;
+       }
+       pkt_dev->entry->proc_fops = &pktgen_if_fops;
+       pkt_dev->entry->data = pkt_dev;
+#ifdef CONFIG_XFRM
+       pkt_dev->ipsmode = XFRM_MODE_TRANSPORT;
+       pkt_dev->ipsproto = IPPROTO_ESP;
+#endif
 
        return add_dev_to_thread(t, pkt_dev);
+out2:
+       dev_put(pkt_dev->odev);
+out1:
+#ifdef CONFIG_XFRM
+       free_SAs(pkt_dev);
+#endif
+       if (pkt_dev->flows)
+               vfree(pkt_dev->flows);
+       kfree(pkt_dev);
+       return err;
 }
 
 static int __init pktgen_create_thread(int cpu)
@@ -3510,8 +3704,8 @@ static int __init pktgen_create_thread(int cpu)
        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)
@@ -3530,7 +3724,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");
@@ -3548,10 +3742,12 @@ 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);
 
+#ifdef CONFIG_XFRM
+       free_SAs(pkt_dev);
+#endif
        if (pkt_dev->flows)
                vfree(pkt_dev->flows);
        kfree(pkt_dev);