]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - net/core/pktgen.c
pktgen: fix skb leak in case of failure
[linux-2.6-omap-h63xx.git] / net / core / pktgen.c
index 2498cdaf8cbe9d8e7511c29e8d8cee121fe51d40..99f656d35b4f5556be314cbb3ec4c732228f5709 100644 (file)
 #include <asm/div64.h>         /* do_div */
 #include <asm/timex.h>
 
-#define VERSION  "pktgen v2.69: Packet Generator for packet performance testing.\n"
+#define VERSION  "pktgen v2.70: Packet Generator for packet performance testing.\n"
 
 #define IP_NAME_SZ 32
 #define MAX_MPLS_LABELS 16 /* This is the max label stack depth */
 #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)
@@ -621,6 +622,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        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*/
@@ -1134,6 +1138,12 @@ static ssize_t pktgen_if_write(struct file *file,
 
                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;
@@ -1895,6 +1905,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)
@@ -1908,7 +1935,7 @@ static int pktgen_setup_dev(struct pktgen_dev *pkt_dev, const char *ifname)
                pkt_dev->odev = NULL;
        }
 
-       odev = dev_get_by_name(&init_net, ifname);
+       odev = pktgen_dev_get_by_name(pkt_dev, ifname);
        if (!odev) {
                printk(KERN_ERR "pktgen: no such netdevice: \"%s\"\n", ifname);
                return -ENODEV;
@@ -1934,6 +1961,8 @@ 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(KERN_ERR "pktgen: ERROR: pkt_dev->odev == NULL in "
                       "setup_inject.\n");
@@ -1942,6 +1971,33 @@ static void pktgen_setup_inject(struct pktgen_dev *pkt_dev)
                return;
        }
 
+       /* make sure that we don't pick a non-existing transmit queue */
+       ntxq = pkt_dev->odev->real_num_tx_queues;
+       if (ntxq <= num_online_cpus() && (pkt_dev->flags & F_QUEUE_MAP_CPU)) {
+               printk(KERN_WARNING "pktgen: WARNING: QUEUE_MAP_CPU "
+                      "disabled because CPU count (%d) exceeds number ",
+                      num_online_cpus());
+               printk(KERN_WARNING "pktgen: WARNING: of tx queues "
+                      "(%d) on %s \n", ntxq, pkt_dev->odev->name);
+               pkt_dev->flags &= ~F_QUEUE_MAP_CPU;
+       }
+       if (ntxq <= pkt_dev->queue_map_min) {
+               printk(KERN_WARNING "pktgen: WARNING: Requested "
+                      "queue_map_min (%d) exceeds number of tx\n",
+                      pkt_dev->queue_map_min);
+               printk(KERN_WARNING "pktgen: WARNING: queues (%d) on "
+                      "%s, resetting\n", ntxq, pkt_dev->odev->name);
+               pkt_dev->queue_map_min = ntxq - 1;
+       }
+       if (ntxq <= pkt_dev->queue_map_max) {
+               printk(KERN_WARNING "pktgen: WARNING: Requested "
+                      "queue_map_max (%d) exceeds number of tx\n",
+                      pkt_dev->queue_map_max);
+               printk(KERN_WARNING "pktgen: WARNING: queues (%d) on "
+                      "%s, resetting\n", 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))
@@ -2129,7 +2185,11 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
 #endif
 static void set_cur_queue_map(struct pktgen_dev *pkt_dev)
 {
-       if (pkt_dev->queue_map_min < pkt_dev->queue_map_max) {
+
+       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() %
@@ -2414,7 +2474,7 @@ static inline int process_ipsec(struct pktgen_dev *pkt_dev,
                                if (ret < 0) {
                                        printk(KERN_ERR "Error expanding "
                                               "ipsec packet %d\n",ret);
-                                       return 0;
+                                       goto err;
                                }
                        }
 
@@ -2424,8 +2484,7 @@ static inline int process_ipsec(struct pktgen_dev *pkt_dev,
                        if (ret) {
                                printk(KERN_ERR "Error creating ipsec "
                                       "packet %d\n",ret);
-                               kfree_skb(skb);
-                               return 0;
+                               goto err;
                        }
                        /* restore ll */
                        eth = (__u8 *) skb_push(skb, ETH_HLEN);
@@ -2434,6 +2493,9 @@ static inline int process_ipsec(struct pktgen_dev *pkt_dev,
                }
        }
        return 1;
+err:
+       kfree_skb(skb);
+       return 0;
 }
 #endif