net: pktgen: packet bursting via skb->xmit_more
[firefly-linux-kernel-4.4.55.git] / net / core / pktgen.c
index 5c728aaf8d6c75568e66730939d6dac50dadf0d9..443256bdcddc8e01c2ba0f0b01c0b0bf78a6608b 100644 (file)
@@ -387,6 +387,7 @@ struct pktgen_dev {
        u16 queue_map_min;
        u16 queue_map_max;
        __u32 skb_priority;     /* skb priority field */
+       unsigned int burst;     /* number of duplicated packets to burst */
        int node;               /* Memory node */
 
 #ifdef CONFIG_XFRM
@@ -613,6 +614,9 @@ static int pktgen_if_show(struct seq_file *seq, void *v)
        if (pkt_dev->traffic_class)
                seq_printf(seq, "     traffic_class: 0x%02x\n", pkt_dev->traffic_class);
 
+       if (pkt_dev->burst > 1)
+               seq_printf(seq, "     burst: %d\n", pkt_dev->burst);
+
        if (pkt_dev->node >= 0)
                seq_printf(seq, "     node: %d\n", pkt_dev->node);
 
@@ -1124,6 +1128,16 @@ static ssize_t pktgen_if_write(struct file *file,
                        pkt_dev->dst_mac_count);
                return count;
        }
+       if (!strcmp(name, "burst")) {
+               len = num_arg(&user_buffer[i], 10, &value);
+               if (len < 0)
+                       return len;
+
+               i += len;
+               pkt_dev->burst = value < 1 ? 1 : value;
+               sprintf(pg_result, "OK: burst=%d", pkt_dev->burst);
+               return count;
+       }
        if (!strcmp(name, "node")) {
                len = num_arg(&user_buffer[i], 10, &value);
                if (len < 0)
@@ -3297,6 +3311,7 @@ static void pktgen_wait_for_skb(struct pktgen_dev *pkt_dev)
 
 static void pktgen_xmit(struct pktgen_dev *pkt_dev)
 {
+       unsigned int burst = ACCESS_ONCE(pkt_dev->burst);
        struct net_device *odev = pkt_dev->odev;
        struct netdev_queue *txq;
        int ret;
@@ -3347,8 +3362,10 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
                pkt_dev->last_ok = 0;
                goto unlock;
        }
-       atomic_inc(&(pkt_dev->skb->users));
-       ret = netdev_start_xmit(pkt_dev->skb, odev, txq, false);
+       atomic_add(burst, &pkt_dev->skb->users);
+
+xmit_more:
+       ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0);
 
        switch (ret) {
        case NETDEV_TX_OK:
@@ -3356,6 +3373,8 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
                pkt_dev->sofar++;
                pkt_dev->seq_num++;
                pkt_dev->tx_bytes += pkt_dev->last_pkt_size;
+               if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq))
+                       goto xmit_more;
                break;
        case NET_XMIT_DROP:
        case NET_XMIT_CN:
@@ -3374,6 +3393,8 @@ static void pktgen_xmit(struct pktgen_dev *pkt_dev)
                atomic_dec(&(pkt_dev->skb->users));
                pkt_dev->last_ok = 0;
        }
+       if (unlikely(burst))
+               atomic_sub(burst, &pkt_dev->skb->users);
 unlock:
        HARD_TX_UNLOCK(odev, txq);
 
@@ -3572,6 +3593,7 @@ static int pktgen_add_device(struct pktgen_thread *t, const char *ifname)
        pkt_dev->svlan_p = 0;
        pkt_dev->svlan_cfi = 0;
        pkt_dev->svlan_id = 0xffff;
+       pkt_dev->burst = 1;
        pkt_dev->node = -1;
 
        err = pktgen_setup_dev(t->net, pkt_dev, ifname);