[SCSI] mptsas : Code cleanup of host page alloc and diag reset.
[safe/jmp/linux-2.6] / net / core / pktgen.c
index b92a322..19b8c20 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Alexey Kuznetsov  <kuznet@ms2.inr.ac.ru>
  * Ben Greear <greearb@candelatech.com>
- * Jens Låås <jens.laas@data.slu.se>
+ * Jens Låås <jens.laas@data.slu.se>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
  *
  * 802.1Q/Q-in-Q support by Francesco Fondelli (FF) <francesco.fondelli@gmail.com>
  *
+ * Fixed src_mac command to set source mac of packet to value specified in
+ * command by Adit Ranadive <adit.262@gmail.com>
+ *
  */
 #include <linux/sys.h>
 #include <linux/types.h>
 #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/wait.h>
 #include <linux/etherdevice.h>
 #include <linux/kthread.h>
+#include <net/net_namespace.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>
+#include <linux/bitops.h>
 #include <asm/io.h>
 #include <asm/dma.h>
 #include <asm/uaccess.h>
 #include <asm/div64.h>         /* do_div */
 #include <asm/timex.h>
 
-#define VERSION  "pktgen v2.68: Packet Generator for packet performance testing.\n"
+#define VERSION  "pktgen v2.70: Packet Generator for packet performance testing.\n"
 
-/* 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 htonl(0x00000100)
 #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 */
+#define F_QUEUE_MAP_RND (1<<13)        /* queue map Random */
+#define F_QUEUE_MAP_CPU (1<<14)        /* queue map mirrors smp_processor_id() */
 
 /* Thread control flag bits */
 #define T_TERMINATE   (1<<0)
@@ -208,8 +216,15 @@ 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;
 };
 
+/* flow flag bits */
+#define F_INIT   (1<<0)                /* flow has been initialized */
+
 struct pktgen_dev {
        /*
         * Try to keep frequent/infrequent used vars. separated.
@@ -229,6 +244,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;
@@ -316,6 +332,7 @@ struct pktgen_dev {
        __be32 cur_daddr;
        __u16 cur_udp_dst;
        __u16 cur_udp_src;
+       __u16 cur_queue_map;
        __u32 cur_pkt_size;
 
        __u8 hh[14];
@@ -342,7 +359,15 @@ struct pktgen_dev {
        unsigned cflows;        /* Concurrent flows (config) */
        unsigned lflow;         /* Flow length  (config) */
        unsigned nflows;        /* accumulated flows (stats) */
+       unsigned curfl;         /* current sequenced flow (state)*/
+
+       u16 queue_map_min;
+       u16 queue_map_max;
 
+#ifdef CONFIG_XFRM
+       __u8    ipsmode;                /* IPSEC mode (config) */
+       __u8    ipsproto;               /* IPSEC type (config) */
+#endif
        char result[512];
 };
 
@@ -359,76 +384,19 @@ struct pktgen_thread {
        struct list_head th_list;
        struct task_struct *tsk;
        char result[512];
-       u32 max_before_softirq; /* We'll call do_softirq to prevent starvation. */
 
        /* Field for thread to receive "posted" events terminate, stop ifs etc. */
 
        u32 control;
-       int pid;
        int cpu;
 
        wait_queue_head_t queue;
+       struct completion start_done;
 };
 
 #define REMOVE 1
 #define FIND   0
 
-/*  This code works around the fact that do_div cannot handle two 64-bit
-    numbers, and regular 64-bit division doesn't work on x86 kernels.
-    --Ben
-*/
-
-#define PG_DIV 0
-
-/* This was emailed to LMKL by: Chris Caputo <ccaputo@alt.net>
- * Function copied/adapted/optimized from:
- *
- *  nemesis.sourceforge.net/browse/lib/static/intmath/ix86/intmath.c.html
- *
- * Copyright 1994, University of Cambridge Computer Laboratory
- * All Rights Reserved.
- *
- */
-static inline s64 divremdi3(s64 x, s64 y, int type)
-{
-       u64 a = (x < 0) ? -x : x;
-       u64 b = (y < 0) ? -y : y;
-       u64 res = 0, d = 1;
-
-       if (b > 0) {
-               while (b < a) {
-                       b <<= 1;
-                       d <<= 1;
-               }
-       }
-
-       do {
-               if (a >= b) {
-                       a -= b;
-                       res += d;
-               }
-               b >>= 1;
-               d >>= 1;
-       }
-       while (d);
-
-       if (PG_DIV == type) {
-               return (((x ^ y) & (1ll << 63)) == 0) ? res : -(s64) res;
-       } else {
-               return ((x & (1ll << 63)) == 0) ? a : -(s64) a;
-       }
-}
-
-/* End of hacks to deal with 64-bit math on x86 */
-
-/** Convert to milliseconds */
-static inline __u64 tv_to_ms(const struct timeval *tv)
-{
-       __u64 ms = tv->tv_usec / 1000;
-       ms += (__u64) tv->tv_sec * (__u64) 1000;
-       return ms;
-}
-
 /** Convert to micro-seconds */
 static inline __u64 tv_to_us(const struct timeval *tv)
 {
@@ -437,51 +405,13 @@ static inline __u64 tv_to_us(const struct timeval *tv)
        return us;
 }
 
-static inline __u64 pg_div(__u64 n, __u32 base)
-{
-       __u64 tmp = n;
-       do_div(tmp, base);
-       /* printk("pktgen: pg_div, n: %llu  base: %d  rv: %llu\n",
-          n, base, tmp); */
-       return tmp;
-}
-
-static inline __u64 pg_div64(__u64 n, __u64 base)
-{
-       __u64 tmp = n;
-/*
- * 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__)
-
-       do_div(tmp, base);
-#else
-       tmp = divremdi3(n, base, PG_DIV);
-#endif
-       return tmp;
-}
-
-static inline __u64 getCurMs(void)
-{
-       struct timeval tv;
-       do_gettimeofday(&tv);
-       return tv_to_ms(&tv);
-}
-
-static inline __u64 getCurUs(void)
+static __u64 getCurUs(void)
 {
        struct timeval tv;
        do_gettimeofday(&tv);
        return tv_to_us(&tv);
 }
 
-static inline __u64 tv_diff(const struct timeval *a, const struct timeval *b)
-{
-       return tv_to_us(a) - tv_to_us(b);
-}
-
 /* old include end */
 
 static char version[] __initdata = VERSION;
@@ -492,6 +422,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t,
                                          const char *ifname);
 static int pktgen_device_event(struct notifier_block *, unsigned long, void *);
 static void pktgen_run_all_threads(void);
+static void pktgen_reset_all_threads(void);
 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);
@@ -550,8 +481,11 @@ static ssize_t pgctrl_write(struct file *file, const char __user * buf,
        else if (!strcmp(data, "start"))
                pktgen_run_all_threads();
 
+       else if (!strcmp(data, "reset"))
+               pktgen_reset_all_threads();
+
        else
-               printk("pktgen: Unknown command: %s\n", data);
+               printk(KERN_WARNING "pktgen: Unknown command: %s\n", data);
 
        err = count;
 
@@ -575,7 +509,6 @@ static const struct file_operations pktgen_fops = {
 
 static int pktgen_if_show(struct seq_file *seq, void *v)
 {
-       int i;
        struct pktgen_dev *pkt_dev = seq->private;
        __u64 sa;
        __u64 stopped;
@@ -595,6 +528,11 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        seq_printf(seq, "     flows: %u flowlen: %u\n", pkt_dev->cflows,
                   pkt_dev->lflow);
 
+       seq_printf(seq,
+                  "     queue_map_min: %u  queue_map_max: %u\n",
+                  pkt_dev->queue_map_min,
+                  pkt_dev->queue_map_max);
+
        if (pkt_dev->flags & F_IPV6) {
                char b1[128], b2[128], b3[128];
                fmt_ip6(b1, pkt_dev->in6_saddr.s6_addr);
@@ -619,19 +557,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
 
        seq_puts(seq, "     src_mac: ");
 
-       if (is_zero_ether_addr(pkt_dev->src_mac))
-               for (i = 0; i < 6; i++)
-                       seq_printf(seq, "%02X%s", pkt_dev->odev->dev_addr[i],
-                                  i == 5 ? "  " : ":");
-       else
-               for (i = 0; i < 6; i++)
-                       seq_printf(seq, "%02X%s", pkt_dev->src_mac[i],
-                                  i == 5 ? "  " : ":");
+       seq_printf(seq, "%pM ",
+                  is_zero_ether_addr(pkt_dev->src_mac) ?
+                            pkt_dev->odev->dev_addr : pkt_dev->src_mac);
 
        seq_printf(seq, "dst_mac: ");
-       for (i = 0; i < 6; i++)
-               seq_printf(seq, "%02X%s", pkt_dev->dst_mac[i],
-                          i == 5 ? "\n" : ":");
+       seq_printf(seq, "%pM\n", pkt_dev->dst_mac);
 
        seq_printf(seq,
                   "     udp_src_min: %d  udp_src_max: %d  udp_dst_min: %d  udp_dst_max: %d\n",
@@ -691,6 +622,24 @@ 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->flags & F_QUEUE_MAP_RND)
+               seq_printf(seq,  "QUEUE_MAP_RND  ");
+
+       if (pkt_dev->flags & F_QUEUE_MAP_CPU)
+               seq_printf(seq,  "QUEUE_MAP_CPU  ");
+
+       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  ");
 
@@ -734,6 +683,8 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        seq_printf(seq, "     cur_udp_dst: %d  cur_udp_src: %d\n",
                   pkt_dev->cur_udp_dst, pkt_dev->cur_udp_src);
 
+       seq_printf(seq, "     cur_queue_map: %u\n", pkt_dev->cur_queue_map);
+
        seq_printf(seq, "     flows: %u\n", pkt_dev->nflows);
 
        if (pkt_dev->result[0])
@@ -880,14 +831,14 @@ static ssize_t pktgen_if_write(struct file *file,
        pg_result = &(pkt_dev->result[0]);
 
        if (count < 1) {
-               printk("pktgen: wrong command format\n");
+               printk(KERN_WARNING "pktgen: wrong command format\n");
                return -EINVAL;
        }
 
        max = count - i;
        tmp = count_trail_chars(&user_buffer[i], max);
        if (tmp < 0) {
-               printk("pktgen: illegal format\n");
+               printk(KERN_WARNING "pktgen: illegal format\n");
                return tmp;
        }
        i += tmp;
@@ -915,7 +866,7 @@ static ssize_t pktgen_if_write(struct file *file,
                if (copy_from_user(tb, user_buffer, count))
                        return -EFAULT;
                tb[count] = 0;
-               printk("pktgen: %s,%lu  buffer -:%s:-\n", name,
+               printk(KERN_DEBUG "pktgen: %s,%lu  buffer -:%s:-\n", name,
                       (unsigned long)count, tb);
        }
 
@@ -1182,6 +1133,25 @@ 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;
+
+               else if (strcmp(f, "QUEUE_MAP_RND") == 0)
+                       pkt_dev->flags |= F_QUEUE_MAP_RND;
+
+               else if (strcmp(f, "!QUEUE_MAP_RND") == 0)
+                       pkt_dev->flags &= ~F_QUEUE_MAP_RND;
+
+               else if (strcmp(f, "QUEUE_MAP_CPU") == 0)
+                       pkt_dev->flags |= F_QUEUE_MAP_CPU;
+
+               else if (strcmp(f, "!QUEUE_MAP_CPU") == 0)
+                       pkt_dev->flags &= ~F_QUEUE_MAP_CPU;
+#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;
 
@@ -1190,7 +1160,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);
@@ -1212,7 +1182,7 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->cur_daddr = pkt_dev->daddr_min;
                }
                if (debug)
-                       printk("pktgen: dst_min set to: %s\n",
+                       printk(KERN_DEBUG "pktgen: dst_min set to: %s\n",
                               pkt_dev->dst_min);
                i += len;
                sprintf(pg_result, "OK: dst_min=%s", pkt_dev->dst_min);
@@ -1235,7 +1205,7 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->cur_daddr = pkt_dev->daddr_max;
                }
                if (debug)
-                       printk("pktgen: dst_max set to: %s\n",
+                       printk(KERN_DEBUG "pktgen: dst_max set to: %s\n",
                               pkt_dev->dst_max);
                i += len;
                sprintf(pg_result, "OK: dst_max=%s", pkt_dev->dst_max);
@@ -1258,7 +1228,7 @@ static ssize_t pktgen_if_write(struct file *file,
                ipv6_addr_copy(&pkt_dev->cur_in6_daddr, &pkt_dev->in6_daddr);
 
                if (debug)
-                       printk("pktgen: dst6 set to: %s\n", buf);
+                       printk(KERN_DEBUG "pktgen: dst6 set to: %s\n", buf);
 
                i += len;
                sprintf(pg_result, "OK: dst6=%s", buf);
@@ -1281,7 +1251,7 @@ static ssize_t pktgen_if_write(struct file *file,
                ipv6_addr_copy(&pkt_dev->cur_in6_daddr,
                               &pkt_dev->min_in6_daddr);
                if (debug)
-                       printk("pktgen: dst6_min set to: %s\n", buf);
+                       printk(KERN_DEBUG "pktgen: dst6_min set to: %s\n", buf);
 
                i += len;
                sprintf(pg_result, "OK: dst6_min=%s", buf);
@@ -1302,7 +1272,7 @@ static ssize_t pktgen_if_write(struct file *file,
                fmt_ip6(buf, pkt_dev->max_in6_daddr.s6_addr);
 
                if (debug)
-                       printk("pktgen: dst6_max set to: %s\n", buf);
+                       printk(KERN_DEBUG "pktgen: dst6_max set to: %s\n", buf);
 
                i += len;
                sprintf(pg_result, "OK: dst6_max=%s", buf);
@@ -1325,7 +1295,7 @@ static ssize_t pktgen_if_write(struct file *file,
                ipv6_addr_copy(&pkt_dev->cur_in6_saddr, &pkt_dev->in6_saddr);
 
                if (debug)
-                       printk("pktgen: src6 set to: %s\n", buf);
+                       printk(KERN_DEBUG "pktgen: src6 set to: %s\n", buf);
 
                i += len;
                sprintf(pg_result, "OK: src6=%s", buf);
@@ -1346,7 +1316,7 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->cur_saddr = pkt_dev->saddr_min;
                }
                if (debug)
-                       printk("pktgen: src_min set to: %s\n",
+                       printk(KERN_DEBUG "pktgen: src_min set to: %s\n",
                               pkt_dev->src_min);
                i += len;
                sprintf(pg_result, "OK: src_min=%s", pkt_dev->src_min);
@@ -1367,7 +1337,7 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->cur_saddr = pkt_dev->saddr_max;
                }
                if (debug)
-                       printk("pktgen: src_max set to: %s\n",
+                       printk(KERN_DEBUG "pktgen: src_max set to: %s\n",
                               pkt_dev->src_max);
                i += len;
                sprintf(pg_result, "OK: src_max=%s", pkt_dev->src_max);
@@ -1416,8 +1386,11 @@ static ssize_t pktgen_if_write(struct file *file,
        }
        if (!strcmp(name, "src_mac")) {
                char *v = valstr;
+               unsigned char old_smac[ETH_ALEN];
                unsigned char *m = pkt_dev->src_mac;
 
+               memcpy(old_smac, pkt_dev->src_mac, ETH_ALEN);
+
                len = strn_len(&user_buffer[i], sizeof(valstr) - 1);
                if (len < 0) {
                        return len;
@@ -1446,6 +1419,10 @@ static ssize_t pktgen_if_write(struct file *file,
                        }
                }
 
+               /* Set up Src MAC */
+               if (compare_ether_addr(old_smac, pkt_dev->src_mac))
+                       memcpy(&(pkt_dev->hh[6]), pkt_dev->src_mac, ETH_ALEN);
+
                sprintf(pg_result, "OK: srcmac");
                return count;
        }
@@ -1481,23 +1458,47 @@ static ssize_t pktgen_if_write(struct file *file,
                return count;
        }
 
+       if (!strcmp(name, "queue_map_min")) {
+               len = num_arg(&user_buffer[i], 5, &value);
+               if (len < 0) {
+                       return len;
+               }
+               i += len;
+               pkt_dev->queue_map_min = value;
+               sprintf(pg_result, "OK: queue_map_min=%u", pkt_dev->queue_map_min);
+               return count;
+       }
+
+       if (!strcmp(name, "queue_map_max")) {
+               len = num_arg(&user_buffer[i], 5, &value);
+               if (len < 0) {
+                       return len;
+               }
+               i += len;
+               pkt_dev->queue_map_max = value;
+               sprintf(pg_result, "OK: queue_map_max=%u", pkt_dev->queue_map_max);
+               return count;
+       }
+
        if (!strcmp(name, "mpls")) {
-               unsigned n, offset;
+               unsigned n, cnt;
+
                len = get_labels(&user_buffer[i], pkt_dev);
-               if (len < 0) { return len; }
+               if (len < 0)
+                       return len;
                i += len;
-               offset = sprintf(pg_result, "OK: mpls=");
+               cnt = sprintf(pg_result, "OK: mpls=");
                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 ? "" : ",");
+                       cnt += sprintf(pg_result + cnt,
+                                      "%08x%s", ntohl(pkt_dev->labels[n]),
+                                      n == pkt_dev->nr_labels-1 ? "" : ",");
 
                if (pkt_dev->nr_labels && pkt_dev->vlan_id != 0xffff) {
                        pkt_dev->vlan_id = 0xffff; /* turn off VLAN/SVLAN */
                        pkt_dev->svlan_id = 0xffff;
 
                        if (debug)
-                               printk("pktgen: VLAN/SVLAN auto turned off\n");
+                               printk(KERN_DEBUG "pktgen: VLAN/SVLAN auto turned off\n");
                }
                return count;
        }
@@ -1512,10 +1513,10 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->vlan_id = value;  /* turn on VLAN */
 
                        if (debug)
-                               printk("pktgen: VLAN turned on\n");
+                               printk(KERN_DEBUG "pktgen: VLAN turned on\n");
 
                        if (debug && pkt_dev->nr_labels)
-                               printk("pktgen: MPLS auto turned off\n");
+                               printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
 
                        pkt_dev->nr_labels = 0;    /* turn off MPLS */
                        sprintf(pg_result, "OK: vlan_id=%u", pkt_dev->vlan_id);
@@ -1524,7 +1525,7 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->svlan_id = 0xffff;
 
                        if (debug)
-                               printk("pktgen: VLAN/SVLAN turned off\n");
+                               printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
                }
                return count;
        }
@@ -1569,10 +1570,10 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->svlan_id = value;  /* turn on SVLAN */
 
                        if (debug)
-                               printk("pktgen: SVLAN turned on\n");
+                               printk(KERN_DEBUG "pktgen: SVLAN turned on\n");
 
                        if (debug && pkt_dev->nr_labels)
-                               printk("pktgen: MPLS auto turned off\n");
+                               printk(KERN_DEBUG "pktgen: MPLS auto turned off\n");
 
                        pkt_dev->nr_labels = 0;    /* turn off MPLS */
                        sprintf(pg_result, "OK: svlan_id=%u", pkt_dev->svlan_id);
@@ -1581,7 +1582,7 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->svlan_id = 0xffff;
 
                        if (debug)
-                               printk("pktgen: VLAN/SVLAN turned off\n");
+                               printk(KERN_DEBUG "pktgen: VLAN/SVLAN turned off\n");
                }
                return count;
        }
@@ -1673,9 +1674,6 @@ 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->tsk->comm, t->max_before_softirq);
-
        seq_printf(seq, "Running: ");
 
        if_lock(t);
@@ -1708,7 +1706,6 @@ static ssize_t pktgen_thread_write(struct file *file,
        int i = 0, max, len, ret;
        char name[40];
        char *pg_result;
-       unsigned long value = 0;
 
        if (count < 1) {
                //      sprintf(pg_result, "Wrong command format");
@@ -1741,10 +1738,11 @@ static ssize_t pktgen_thread_write(struct file *file,
        i += len;
 
        if (debug)
-               printk("pktgen: t=%s, count=%lu\n", name, (unsigned long)count);
+               printk(KERN_DEBUG "pktgen: t=%s, count=%lu\n",
+                      name, (unsigned long)count);
 
        if (!t) {
-               printk("pktgen: ERROR: No thread\n");
+               printk(KERN_ERR "pktgen: ERROR: No thread\n");
                ret = -EINVAL;
                goto out;
        }
@@ -1781,12 +1779,8 @@ static ssize_t pktgen_thread_write(struct file *file,
        }
 
        if (!strcmp(name, "max_before_softirq")) {
-               len = num_arg(&user_buffer[i], 10, &value);
-               mutex_lock(&pktgen_thread_lock);
-               t->max_before_softirq = value;
-               mutex_unlock(&pktgen_thread_lock);
+               sprintf(pg_result, "OK: Note! max_before_softirq is obsoleted -- Do not use");
                ret = count;
-               sprintf(pg_result, "OK: max_before_softirq=%lu", value);
                goto out;
        }
 
@@ -1855,8 +1849,8 @@ static void pktgen_mark_device(const char *ifname)
                mutex_lock(&pktgen_thread_lock);
 
                if (++i >= max_tries) {
-                       printk("pktgen_mark_device: timed out after waiting "
-                              "%d msec for device %s to be removed\n",
+                       printk(KERN_ERR "pktgen_mark_device: timed out after "
+                              "waiting %d msec for device %s to be removed\n",
                               msec_per_try * i, ifname);
                        break;
                }
@@ -1894,6 +1888,9 @@ static int pktgen_device_event(struct notifier_block *unused,
 {
        struct net_device *dev = ptr;
 
+       if (!net_eq(dev_net(dev), &init_net))
+               return NOTIFY_DONE;
+
        /* It is OK that we do not hold the group lock right now,
         * as we run under the RTNL lock.
         */
@@ -1911,6 +1908,23 @@ static int pktgen_device_event(struct notifier_block *unused,
        return NOTIFY_DONE;
 }
 
+static struct net_device *pktgen_dev_get_by_name(struct pktgen_dev *pkt_dev, const char *ifname)
+{
+       char b[IFNAMSIZ+5];
+       int i = 0;
+
+       for(i=0; ifname[i] != '@'; i++) {
+               if(i == IFNAMSIZ)
+                       break;
+
+               b[i] = ifname[i];
+       }
+       b[i] = 0;
+
+       return dev_get_by_name(&init_net, b);
+}
+
+
 /* Associate pktgen_dev with a device. */
 
 static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
@@ -1924,17 +1938,17 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
                pkt_dev->odev = NULL;
        }
 
-       odev = dev_get_by_name(ifname);
+       odev = pktgen_dev_get_by_name(pkt_dev, ifname);
        if (!odev) {
-               printk("pktgen: no such netdevice: \"%s\"\n", ifname);
+               printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname);
                return -ENODEV;
        }
 
        if (odev->type != ARPHRD_ETHER) {
-               printk("pktgen: not an ethernet device: \"%s\"\n", ifname);
+               printk(KERN_ERR "pktgen: not an ethernet device: \"%s\"\n", ifname);
                err = -EINVAL;
        } else if (!netif_running(odev)) {
-               printk("pktgen: device is down: \"%s\"\n", ifname);
+               printk(KERN_ERR "pktgen: device is down: \"%s\"\n", ifname);
                err = -ENETDOWN;
        } else {
                pkt_dev->odev = odev;
@@ -1950,13 +1964,36 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
  */
 static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
 {
+       int ntxq;
+
        if (!pkt_dev->odev) {
-               printk("pktgen: ERROR: pkt_dev->odev == NULL in setup_inject.\n");
+               printk(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in "
+                      "setup_inject.\n");
                sprintf(pkt_dev->result,
                        "ERROR: pkt_dev->odev == NULL in setup_inject.\n");
                return;
        }
 
+       /* make sure that we don't pick a non-existing transmit queue */
+       ntxq = pkt_dev->odev->real_num_tx_queues;
+
+       if (ntxq <= pkt_dev->queue_map_min) {
+               printk(KERN_WARNING "pktgen: WARNING: Requested "
+                      "queue_map_min (zero-based) (%d) exceeds valid range "
+                      "[0 - %d] for (%d) queues on %s, resetting\n",
+                      pkt_dev->queue_map_min, (ntxq ?: 1)- 1, ntxq,
+                      pkt_dev->odev->name);
+               pkt_dev->queue_map_min = ntxq - 1;
+       }
+       if (pkt_dev->queue_map_max >= ntxq) {
+               printk(KERN_WARNING "pktgen: WARNING: Requested "
+                      "queue_map_max (zero-based) (%d) exceeds valid range "
+                      "[0 - %d] for (%d) queues on %s, resetting\n",
+                      pkt_dev->queue_map_max, (ntxq ?: 1)- 1, ntxq,
+                      pkt_dev->odev->name);
+               pkt_dev->queue_map_max = ntxq - 1;
+       }
+
        /* Default to the interface's mac if not explicitly set. */
 
        if (is_zero_ether_addr(pkt_dev->src_mac))
@@ -2013,7 +2050,8 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
                        }
                        rcu_read_unlock();
                        if (err)
-                               printk("pktgen: ERROR: IPv6 link address not availble.\n");
+                               printk(KERN_ERR "pktgen: ERROR: IPv6 link "
+                                      "address not availble.\n");
                }
 #endif
        } else {
@@ -2057,13 +2095,11 @@ static void spin(struct pktgen_dev *pkt_dev, __u64 spin_until_us)
        __u64 now;
 
        start = now = getCurUs();
-       printk(KERN_INFO "sleeping for %d\n", (int)(spin_until_us - now));
        while (now < spin_until_us) {
                /* TODO: optimize sleeping behavior */
                if (spin_until_us - now > jiffies_to_usecs(1) + 1)
                        schedule_timeout_interruptible(1);
                else if (spin_until_us - now > 100) {
-                       do_softirq();
                        if (!pkt_dev->running)
                                return;
                        if (need_resched())
@@ -2076,6 +2112,97 @@ 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->flows[flow].flags = 0;
+                       pkt_dev->curfl += 1;
+                       if (pkt_dev->curfl >= pkt_dev->cflows)
+                               pkt_dev->curfl = 0; /*reset */
+               }
+       } else {
+               flow = random32() % pkt_dev->cflows;
+               pkt_dev->curfl = flow;
+
+               if (pkt_dev->flows[flow].count > pkt_dev->lflow) {
+                       pkt_dev->flows[flow].count = 0;
+                       pkt_dev->flows[flow].flags = 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 ...
+*/
+static 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(&init_net,
+                                       (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
+static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
+{
+
+       if (pkt_dev->flags & F_QUEUE_MAP_CPU)
+               pkt_dev->cur_queue_map = smp_processor_id();
+
+       else if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) {
+               __u16 t;
+               if (pkt_dev->flags & F_QUEUE_MAP_RND) {
+                       t = random32() %
+                               (pkt_dev->queue_map_max -
+                                pkt_dev->queue_map_min + 1)
+                               + pkt_dev->queue_map_min;
+               } else {
+                       t = pkt_dev->cur_queue_map + 1;
+                       if (t > pkt_dev->queue_map_max)
+                               t = pkt_dev->queue_map_min;
+               }
+               pkt_dev->cur_queue_map = t;
+       }
+       pkt_dev->cur_queue_map  = pkt_dev->cur_queue_map % pkt_dev->odev->real_num_tx_queues;
+}
+
 /* Increment/randomize headers according to flags and current values
  * for IP src/dest, UDP src/dst port, MAC-Addr src/dst
  */
@@ -2085,12 +2212,8 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
        __u32 imx;
        int flow = 0;
 
-       if (pkt_dev->cflows) {
-               flow = random32() % 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) {
@@ -2101,7 +2224,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                        mc = random32() % pkt_dev->src_mac_count;
                else {
                        mc = pkt_dev->cur_src_mac_offset++;
-                       if (pkt_dev->cur_src_mac_offset >
+                       if (pkt_dev->cur_src_mac_offset >=
                            pkt_dev->src_mac_count)
                                pkt_dev->cur_src_mac_offset = 0;
                }
@@ -2128,7 +2251,7 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
 
                else {
                        mc = pkt_dev->cur_dst_mac_offset++;
-                       if (pkt_dev->cur_dst_mac_offset >
+                       if (pkt_dev->cur_dst_mac_offset >=
                            pkt_dev->dst_mac_count) {
                                pkt_dev->cur_dst_mac_offset = 0;
                        }
@@ -2206,7 +2329,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);
@@ -2219,9 +2342,11 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                                        t = random32() % (imx - imn) + imn;
                                        s = htonl(t);
 
-                                       while (LOOPBACK(s) || MULTICAST(s)
-                                              || BADCLASS(s) || ZERONET(s)
-                                              || LOCAL_MCAST(s)) {
+                                       while (ipv4_is_loopback(s) ||
+                                              ipv4_is_multicast(s) ||
+                                              ipv4_is_lbcast(s) ||
+                                              ipv4_is_zeronet(s) ||
+                                              ipv4_is_local_multicast(s)) {
                                                t = random32() % (imx - imn) + imn;
                                                s = htonl(t);
                                        }
@@ -2236,8 +2361,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++;
                        }
                }
@@ -2275,9 +2405,98 @@ static void mod_cur_headers(struct pktgen_dev *pkt_dev)
                pkt_dev->cur_pkt_size = t;
        }
 
+       set_cur_queue_map(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->outer_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++;
+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->cflows; 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(KERN_ERR "Error expanding "
+                                              "ipsec packet %d\n",ret);
+                                       goto err;
+                               }
+                       }
+
+                       /* ipsec is not expecting ll header */
+                       skb_pull(skb, ETH_HLEN);
+                       ret = pktgen_output_ipsec(skb, pkt_dev);
+                       if (ret) {
+                               printk(KERN_ERR "Error creating ipsec "
+                                      "packet %d\n",ret);
+                               goto err;
+                       }
+                       /* restore ll */
+                       eth = (__u8 *) skb_push(skb, ETH_HLEN);
+                       memcpy(eth, pkt_dev->hh, 12);
+                       *(u16 *) & eth[12] = protocol;
+               }
+       }
+       return 1;
+err:
+       kfree_skb(skb);
+       return 0;
+}
+#endif
+
 static void mpls_push(__be32 *mpls, struct pktgen_dev *pkt_dev)
 {
        unsigned i;
@@ -2309,7 +2528,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        __be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
        __be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
        __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
-
+       u16 queue_map;
 
        if (pkt_dev->nr_labels)
                protocol = htons(ETH_P_MPLS_UC);
@@ -2320,13 +2539,12 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        /* Update any of the values, used when we're incrementing various
         * fields.
         */
+       queue_map = pkt_dev->cur_queue_map;
        mod_cur_headers(pkt_dev);
 
        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;
@@ -2360,7 +2578,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        skb->network_header = skb->tail;
        skb->transport_header = skb->network_header + sizeof(struct iphdr);
        skb_put(skb, sizeof(struct iphdr) + sizeof(struct udphdr));
-
+       skb_set_queue_mapping(skb, queue_map);
        iph = ip_hdr(skb);
        udph = udp_hdr(skb);
 
@@ -2369,7 +2587,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
 
        /* 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);
 
@@ -2392,8 +2610,7 @@ static struct sk_buff *fill_packet_ipv4(struct net_device *odev,
        iph->check = ip_fast_csum((void *)iph, iph->ihl);
        skb->protocol = protocol;
        skb->mac_header = (skb->network_header - ETH_HLEN -
-                          pkt_dev->nr_labels * sizeof(u32) -
-                          VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev));
+                          pkt_dev->pkt_overhead);
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
 
@@ -2464,6 +2681,11 @@ 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;
 }
 
@@ -2485,6 +2707,7 @@ static unsigned int scan_ip6(const char *s, char ip[16])
        unsigned int prefixlen = 0;
        unsigned int suffixlen = 0;
        __be32 tmp;
+       char *pos;
 
        for (i = 0; i < 16; i++)
                ip[i] = 0;
@@ -2499,12 +2722,9 @@ static unsigned int scan_ip6(const char *s, char ip[16])
                        }
                        s++;
                }
-               {
-                       char *tmp;
-                       u = simple_strtoul(s, &tmp, 16);
-                       i = tmp - s;
-               }
 
+               u = simple_strtoul(s, &pos, 16);
+               i = pos - s;
                if (!i)
                        return 0;
                if (prefixlen == 12 && s[i] == '.') {
@@ -2532,11 +2752,9 @@ static unsigned int scan_ip6(const char *s, char ip[16])
                        len++;
                } else if (suffixlen != 0)
                        break;
-               {
-                       char *tmp;
-                       u = simple_strtol(s, &tmp, 16);
-                       i = tmp - s;
-               }
+
+               u = simple_strtol(s, &pos, 16);
+               i = pos - s;
                if (!i) {
                        if (*s)
                                len--;
@@ -2650,6 +2868,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        __be16 *vlan_encapsulated_proto = NULL;  /* packet type ID field (or len) for VLAN tag */
        __be16 *svlan_tci = NULL;                /* Encapsulates priority and SVLAN ID */
        __be16 *svlan_encapsulated_proto = NULL; /* packet type ID field (or len) for SVLAN tag */
+       u16 queue_map;
 
        if (pkt_dev->nr_labels)
                protocol = htons(ETH_P_MPLS_UC);
@@ -2660,12 +2879,11 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        /* Update any of the values, used when we're incrementing various
         * fields.
         */
+       queue_map = pkt_dev->cur_queue_map;
        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;
@@ -2699,7 +2917,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        skb->network_header = skb->tail;
        skb->transport_header = skb->network_header + sizeof(struct ipv6hdr);
        skb_put(skb, sizeof(struct ipv6hdr) + sizeof(struct udphdr));
-
+       skb_set_queue_mapping(skb, queue_map);
        iph = ipv6_hdr(skb);
        udph = udp_hdr(skb);
 
@@ -2709,7 +2927,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);
@@ -2739,8 +2957,7 @@ static struct sk_buff *fill_packet_ipv6(struct net_device *odev,
        ipv6_addr_copy(&iph->saddr, &pkt_dev->cur_in6_saddr);
 
        skb->mac_header = (skb->network_header - ETH_HLEN -
-                          pkt_dev->nr_labels * sizeof(u32) -
-                          VLAN_TAG_SIZE(pkt_dev) - SVLAN_TAG_SIZE(pkt_dev));
+                          pkt_dev->pkt_overhead);
        skb->protocol = protocol;
        skb->dev = odev;
        skb->pkt_type = PACKET_HOST;
@@ -2858,6 +3075,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++;
@@ -2955,6 +3173,24 @@ static void pktgen_run_all_threads(void)
        pktgen_wait_all_threads_run();
 }
 
+static void pktgen_reset_all_threads(void)
+{
+       struct pktgen_thread *t;
+
+       pr_debug("pktgen: entering pktgen_reset_all_threads.\n");
+
+       mutex_lock(&pktgen_thread_lock);
+
+       list_for_each_entry(t, &pktgen_threads, th_list)
+               t->control |= (T_REMDEVALL);
+
+       mutex_unlock(&pktgen_thread_lock);
+
+       schedule_timeout_interruptible(msecs_to_jiffies(125));  /* Propagate thread->control  */
+
+       pktgen_wait_all_threads_run();
+}
+
 static void show_results(struct pktgen_dev *pkt_dev, int nr_frags)
 {
        __u64 total_us, bps, mbps, pps, idle;
@@ -2998,8 +3234,8 @@ static int pktgen_stop_device(struct pktgen_dev *pkt_dev)
        int nr_frags = pkt_dev->skb ? skb_shinfo(pkt_dev->skb)->nr_frags : -1;
 
        if (!pkt_dev->running) {
-               printk("pktgen: interface: %s is already stopped\n",
-                      pkt_dev->odev->name);
+               printk(KERN_WARNING "pktgen: interface: %s is already "
+                      "stopped\n", pkt_dev->odev->name);
                return -EINVAL;
        }
 
@@ -3039,8 +3275,7 @@ static void pktgen_stop(struct pktgen_thread *t)
 
        list_for_each_entry(pkt_dev, &t->if_list, list) {
                pktgen_stop_device(pkt_dev);
-               if (pkt_dev->skb)
-                       kfree_skb(pkt_dev->skb);
+               kfree_skb(pkt_dev->skb);
 
                pkt_dev->skb = NULL;
        }
@@ -3067,8 +3302,7 @@ static void pktgen_rem_one_if(struct pktgen_thread *t)
                if (!cur->removal_mark)
                        continue;
 
-               if (cur->skb)
-                       kfree_skb(cur->skb);
+               kfree_skb(cur->skb);
                cur->skb = NULL;
 
                pktgen_remove_device(t, cur);
@@ -3092,8 +3326,7 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t)
        list_for_each_safe(q, n, &t->if_list) {
                cur = list_entry(q, struct pktgen_dev, list);
 
-               if (cur->skb)
-                       kfree_skb(cur->skb);
+               kfree_skb(cur->skb);
                cur->skb = NULL;
 
                pktgen_remove_device(t, cur);
@@ -3117,12 +3350,14 @@ static void pktgen_rem_thread(struct pktgen_thread *t)
 
 static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 {
-       struct net_device *odev = NULL;
+       struct net_device *odev = pkt_dev->odev;
+       int (*xmit)(struct sk_buff *, struct net_device *)
+               = odev->netdev_ops->ndo_start_xmit;
+       struct netdev_queue *txq;
        __u64 idle_start = 0;
+       u16 queue_map;
        int ret;
 
-       odev = pkt_dev->odev;
-
        if (pkt_dev->delay_us || pkt_dev->delay_ns) {
                u64 now;
 
@@ -3140,13 +3375,22 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                }
        }
 
-       if (netif_queue_stopped(odev) || need_resched()) {
+       if (!pkt_dev->skb) {
+               set_cur_queue_map(pkt_dev);
+               queue_map = pkt_dev->cur_queue_map;
+       } else {
+               queue_map = skb_get_queue_mapping(pkt_dev->skb);
+       }
+
+       txq = netdev_get_tx_queue(odev, queue_map);
+       if (netif_tx_queue_stopped(txq) ||
+           netif_tx_queue_frozen(txq) ||
+           need_resched()) {
                idle_start = getCurUs();
 
                if (!netif_running(odev)) {
                        pktgen_stop_device(pkt_dev);
-                       if (pkt_dev->skb)
-                               kfree_skb(pkt_dev->skb);
+                       kfree_skb(pkt_dev->skb);
                        pkt_dev->skb = NULL;
                        goto out;
                }
@@ -3155,7 +3399,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_tx_queue_stopped(txq) ||
+                   netif_tx_queue_frozen(txq)) {
                        pkt_dev->next_tx_us = getCurUs();       /* TODO */
                        pkt_dev->next_tx_ns = 0;
                        goto out;       /* Try the next interface */
@@ -3166,12 +3411,12 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                if ((++pkt_dev->clone_count >= pkt_dev->clone_skb)
                    || (!pkt_dev->skb)) {
                        /* build a new pkt */
-                       if (pkt_dev->skb)
-                               kfree_skb(pkt_dev->skb);
+                       kfree_skb(pkt_dev->skb);
 
                        pkt_dev->skb = fill_packet(odev, pkt_dev);
                        if (pkt_dev->skb == NULL) {
-                               printk("pktgen: ERROR: couldn't allocate skb in fill_packet.\n");
+                               printk(KERN_ERR "pktgen: ERROR: couldn't "
+                                      "allocate skb in fill_packet.\n");
                                schedule();
                                pkt_dev->clone_count--; /* back out increment, OOM */
                                goto out;
@@ -3181,13 +3426,19 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                }
        }
 
-       netif_tx_lock_bh(odev);
-       if (!netif_queue_stopped(odev)) {
+       /* fill_packet() might have changed the queue */
+       queue_map = skb_get_queue_mapping(pkt_dev->skb);
+       txq = netdev_get_tx_queue(odev, queue_map);
+
+       __netif_tx_lock_bh(txq);
+       if (!netif_tx_queue_stopped(txq) &&
+           !netif_tx_queue_frozen(txq)) {
 
                atomic_inc(&(pkt_dev->skb->users));
              retry_now:
-               ret = odev->hard_start_xmit(pkt_dev->skb, odev);
+               ret = (*xmit)(pkt_dev->skb, odev);
                if (likely(ret == NETDEV_TX_OK)) {
+                       txq_trans_update(txq);
                        pkt_dev->last_ok = 1;
                        pkt_dev->sofar++;
                        pkt_dev->seq_num++;
@@ -3226,7 +3477,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                pkt_dev->next_tx_ns = 0;
        }
 
-       netif_tx_unlock_bh(odev);
+       __netif_tx_unlock_bh(txq);
 
        /* If pkt_dev->count is zero, then run forever */
        if ((pkt_dev->count != 0) && (pkt_dev->sofar >= pkt_dev->count)) {
@@ -3243,8 +3494,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
                /* Done with this */
                pktgen_stop_device(pkt_dev);
-               if (pkt_dev->skb)
-                       kfree_skb(pkt_dev->skb);
+               kfree_skb(pkt_dev->skb);
                pkt_dev->skb = NULL;
        }
 out:;
@@ -3260,21 +3510,18 @@ static int pktgen_thread_worker(void *arg)
        struct pktgen_thread *t = arg;
        struct pktgen_dev *pkt_dev = NULL;
        int cpu = t->cpu;
-       u32 max_before_softirq;
-       u32 tx_since_softirq = 0;
 
        BUG_ON(smp_processor_id() != cpu);
 
        init_waitqueue_head(&t->queue);
+       complete(&t->start_done);
 
-       t->pid = current->pid;
-
-       pr_debug("pktgen: starting pktgen/%d:  pid=%d\n", cpu, current->pid);
-
-       max_before_softirq = t->max_before_softirq;
+       pr_debug("pktgen: starting pktgen/%d:  pid=%d\n", cpu, task_pid_nr(current));
 
        set_current_state(TASK_INTERRUPTIBLE);
 
+       set_freezable();
+
        while (!kthread_should_stop()) {
                pkt_dev = next_to_run(t);
 
@@ -3289,24 +3536,9 @@ static int pktgen_thread_worker(void *arg)
 
                __set_current_state(TASK_RUNNING);
 
-               if (pkt_dev) {
-
+               if (pkt_dev)
                        pktgen_xmit(pkt_dev);
 
-                       /*
-                        * We like to stay RUNNING but must also give
-                        * others fair share.
-                        */
-
-                       tx_since_softirq += pkt_dev->last_ok;
-
-                       if (tx_since_softirq > max_before_softirq) {
-                               if (local_softirq_pending())
-                                       do_softirq();
-                               tx_since_softirq = 0;
-                       }
-               }
-
                if (t->control & T_STOP) {
                        pktgen_stop(t);
                        t->control &= ~(T_STOP);
@@ -3373,7 +3605,8 @@ static int add_dev_to_thread(struct pktgen_thread *t,
        if_lock(t);
 
        if (pkt_dev->pg_thread) {
-               printk("pktgen: ERROR:  already assigned to a thread.\n");
+               printk(KERN_ERR "pktgen: ERROR: already assigned "
+                      "to a thread.\n");
                rv = -EBUSY;
                goto out;
        }
@@ -3398,7 +3631,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
 
        pkt_dev = __pktgen_NN_threads(ifname, FIND);
        if (pkt_dev) {
-               printk("pktgen: ERROR: interface already used.\n");
+               printk(KERN_ERR "pktgen: ERROR: interface already used.\n");
                return -EBUSY;
        }
 
@@ -3438,22 +3671,27 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
        if (err)
                goto out1;
 
-       pkt_dev->entry = create_proc_entry(ifname, 0600, pg_proc_dir);
+       pkt_dev->entry = proc_create_data(ifname, 0600, pg_proc_dir,
+                                         &pktgen_if_fops, pkt_dev);
        if (!pkt_dev->entry) {
-               printk("pktgen: cannot create %s/%s procfs entry.\n",
+               printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
                       PG_PROC_DIR, ifname);
                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:
-       if (pkt_dev->flows)
-               vfree(pkt_dev->flows);
+#ifdef CONFIG_XFRM
+       free_SAs(pkt_dev);
+#endif
+       vfree(pkt_dev->flows);
        kfree(pkt_dev);
        return err;
 }
@@ -3466,7 +3704,8 @@ static int __init pktgen_create_thread(int cpu)
 
        t = kzalloc(sizeof(struct pktgen_thread), GFP_KERNEL);
        if (!t) {
-               printk("pktgen: ERROR: out of memory, can't create new thread.\n");
+               printk(KERN_ERR "pktgen: ERROR: out of memory, can't "
+                      "create new thread.\n");
                return -ENOMEM;
        }
 
@@ -3476,10 +3715,12 @@ static int __init pktgen_create_thread(int cpu)
        INIT_LIST_HEAD(&t->if_list);
 
        list_add_tail(&t->th_list, &pktgen_threads);
+       init_completion(&t->start_done);
 
        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);
+               printk(KERN_ERR "pktgen: kernel_thread() failed "
+                      "for cpu %d\n", t->cpu);
                list_del(&t->th_list);
                kfree(t);
                return PTR_ERR(p);
@@ -3487,9 +3728,10 @@ static int __init pktgen_create_thread(int cpu)
        kthread_bind(p, cpu);
        t->tsk = p;
 
-       pe = create_proc_entry(t->tsk->comm, 0600, pg_proc_dir);
+       pe = proc_create_data(t->tsk->comm, 0600, pg_proc_dir,
+                             &pktgen_thread_fops, t);
        if (!pe) {
-               printk("pktgen: cannot create %s/%s procfs entry.\n",
+               printk(KERN_ERR "pktgen: cannot create %s/%s procfs entry.\n",
                       PG_PROC_DIR, t->tsk->comm);
                kthread_stop(p);
                list_del(&t->th_list);
@@ -3497,10 +3739,8 @@ static int __init pktgen_create_thread(int cpu)
                return -EINVAL;
        }
 
-       pe->proc_fops = &pktgen_thread_fops;
-       pe->data = t;
-
        wake_up_process(p);
+       wait_for_completion(&t->start_done);
 
        return 0;
 }
@@ -3528,7 +3768,8 @@ static int pktgen_remove_device(struct pktgen_thread *t,
        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");
+               printk(KERN_WARNING "pktgen: WARNING: trying to remove a "
+                      "running interface, stopping it now.\n");
                pktgen_stop_device(pkt_dev);
        }
 
@@ -3546,8 +3787,10 @@ static int pktgen_remove_device(struct pktgen_thread *t,
        if (pkt_dev->entry)
                remove_proc_entry(pkt_dev->entry->name, pg_proc_dir);
 
-       if (pkt_dev->flows)
-               vfree(pkt_dev->flows);
+#ifdef CONFIG_XFRM
+       free_SAs(pkt_dev);
+#endif
+       vfree(pkt_dev->flows);
        kfree(pkt_dev);
        return 0;
 }
@@ -3557,24 +3800,20 @@ static int __init pg_init(void)
        int cpu;
        struct proc_dir_entry *pe;
 
-       printk(version);
+       printk(KERN_INFO "%s", version);
 
-       pg_proc_dir = proc_mkdir(PG_PROC_DIR, proc_net);
+       pg_proc_dir = proc_mkdir(PG_PROC_DIR, init_net.proc_net);
        if (!pg_proc_dir)
                return -ENODEV;
-       pg_proc_dir->owner = THIS_MODULE;
 
-       pe = create_proc_entry(PGCTRL, 0600, pg_proc_dir);
+       pe = proc_create(PGCTRL, 0600, pg_proc_dir, &pktgen_fops);
        if (pe == NULL) {
-               printk("pktgen: ERROR: cannot create %s procfs entry.\n",
-                      PGCTRL);
-               proc_net_remove(PG_PROC_DIR);
+               printk(KERN_ERR "pktgen: ERROR: cannot create %s "
+                      "procfs entry.\n", PGCTRL);
+               proc_net_remove(&init_net, PG_PROC_DIR);
                return -EINVAL;
        }
 
-       pe->proc_fops = &pktgen_fops;
-       pe->data = NULL;
-
        /* Register us to receive netdevice events */
        register_netdevice_notifier(&pktgen_notifier_block);
 
@@ -3583,15 +3822,16 @@ static int __init pg_init(void)
 
                err = pktgen_create_thread(cpu);
                if (err)
-                       printk("pktgen: WARNING: Cannot create thread for cpu %d (%d)\n",
-                                       cpu, err);
+                       printk(KERN_WARNING "pktgen: WARNING: Cannot create "
+                              "thread for cpu %d (%d)\n", cpu, err);
        }
 
        if (list_empty(&pktgen_threads)) {
-               printk("pktgen: ERROR: Initialization failed for all threads\n");
+               printk(KERN_ERR "pktgen: ERROR: Initialization failed for "
+                      "all threads\n");
                unregister_netdevice_notifier(&pktgen_notifier_block);
                remove_proc_entry(PGCTRL, pg_proc_dir);
-               proc_net_remove(PG_PROC_DIR);
+               proc_net_remove(&init_net, PG_PROC_DIR);
                return -ENODEV;
        }
 
@@ -3618,7 +3858,7 @@ static void __exit pg_cleanup(void)
 
        /* Clean up proc file system */
        remove_proc_entry(PGCTRL, pg_proc_dir);
-       proc_net_remove(PG_PROC_DIR);
+       proc_net_remove(&init_net, PG_PROC_DIR);
 }
 
 module_init(pg_init);