Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: pktgen: packet bursting via skb->xmit_more

This patch demonstrates the effect of delaying update of HW tailptr.
(based on earlier patch by Jesper)

burst=1 is the default. It sends one packet with xmit_more=false
burst=2 sends one packet with xmit_more=true and
2nd copy of the same packet with xmit_more=false
burst=3 sends two copies of the same packet with xmit_more=true and
3rd copy with xmit_more=false

Performance with ixgbe (usec 30):
burst=1 tx:9.2 Mpps
burst=2 tx:13.5 Mpps
burst=3 tx:14.5 Mpps full 10G line rate

Signed-off-by: Alexei Starovoitov <ast@plumgrid.com>
Signed-off-by: Eric Dumazet <edumazet@google.com>
Acked-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Alexei Starovoitov and committed by
David S. Miller
38b2cf29 775dd692

+27 -2
+3
Documentation/networking/pktgen.txt
··· 99 99 100 100 pgset "clone_skb 1" sets the number of copies of the same packet 101 101 pgset "clone_skb 0" use single SKB for all transmits 102 + pgset "burst 8" uses xmit_more API to queue 8 copies of the same 103 + packet and update HW tx queue tail pointer once. 104 + "burst 1" is the default 102 105 pgset "pkt_size 9014" sets packet size to 9014 103 106 pgset "frags 5" packet will consist of 5 fragments 104 107 pgset "count 200000" sets number of packets to send, set to zero
+24 -2
net/core/pktgen.c
··· 387 387 u16 queue_map_min; 388 388 u16 queue_map_max; 389 389 __u32 skb_priority; /* skb priority field */ 390 + unsigned int burst; /* number of duplicated packets to burst */ 390 391 int node; /* Memory node */ 391 392 392 393 #ifdef CONFIG_XFRM ··· 613 612 614 613 if (pkt_dev->traffic_class) 615 614 seq_printf(seq, " traffic_class: 0x%02x\n", pkt_dev->traffic_class); 615 + 616 + if (pkt_dev->burst > 1) 617 + seq_printf(seq, " burst: %d\n", pkt_dev->burst); 616 618 617 619 if (pkt_dev->node >= 0) 618 620 seq_printf(seq, " node: %d\n", pkt_dev->node); ··· 1126 1122 } 1127 1123 sprintf(pg_result, "OK: dst_mac_count=%d", 1128 1124 pkt_dev->dst_mac_count); 1125 + return count; 1126 + } 1127 + if (!strcmp(name, "burst")) { 1128 + len = num_arg(&user_buffer[i], 10, &value); 1129 + if (len < 0) 1130 + return len; 1131 + 1132 + i += len; 1133 + pkt_dev->burst = value < 1 ? 1 : value; 1134 + sprintf(pg_result, "OK: burst=%d", pkt_dev->burst); 1129 1135 return count; 1130 1136 } 1131 1137 if (!strcmp(name, "node")) { ··· 3311 3297 3312 3298 static void pktgen_xmit(struct pktgen_dev *pkt_dev) 3313 3299 { 3300 + unsigned int burst = ACCESS_ONCE(pkt_dev->burst); 3314 3301 struct net_device *odev = pkt_dev->odev; 3315 3302 struct netdev_queue *txq; 3316 3303 int ret; ··· 3362 3347 pkt_dev->last_ok = 0; 3363 3348 goto unlock; 3364 3349 } 3365 - atomic_inc(&(pkt_dev->skb->users)); 3366 - ret = netdev_start_xmit(pkt_dev->skb, odev, txq, false); 3350 + atomic_add(burst, &pkt_dev->skb->users); 3351 + 3352 + xmit_more: 3353 + ret = netdev_start_xmit(pkt_dev->skb, odev, txq, --burst > 0); 3367 3354 3368 3355 switch (ret) { 3369 3356 case NETDEV_TX_OK: ··· 3373 3356 pkt_dev->sofar++; 3374 3357 pkt_dev->seq_num++; 3375 3358 pkt_dev->tx_bytes += pkt_dev->last_pkt_size; 3359 + if (burst > 0 && !netif_xmit_frozen_or_drv_stopped(txq)) 3360 + goto xmit_more; 3376 3361 break; 3377 3362 case NET_XMIT_DROP: 3378 3363 case NET_XMIT_CN: ··· 3393 3374 atomic_dec(&(pkt_dev->skb->users)); 3394 3375 pkt_dev->last_ok = 0; 3395 3376 } 3377 + if (unlikely(burst)) 3378 + atomic_sub(burst, &pkt_dev->skb->users); 3396 3379 unlock: 3397 3380 HARD_TX_UNLOCK(odev, txq); 3398 3381 ··· 3593 3572 pkt_dev->svlan_p = 0; 3594 3573 pkt_dev->svlan_cfi = 0; 3595 3574 pkt_dev->svlan_id = 0xffff; 3575 + pkt_dev->burst = 1; 3596 3576 pkt_dev->node = -1; 3597 3577 3598 3578 err = pktgen_setup_dev(t->net, pkt_dev, ifname);