[dpdk-dev] examples: new txburst application

Message ID 1416335575-30717-1-git-send-email-bhavesh@vmware.com (mailing list archive)
State Rejected, archived
Headers

Commit Message

Bhavesh Davda Nov. 18, 2014, 6:32 p.m. UTC
  Test application to transmit 32-packet bursts of 220-byte UDP packets every
50 us, approximating 240,000 pps. We found it useful for testing hypervisor
performance for a transmit-heavy but bursty workload in a VM with DPDK.

Signed-off-by: Bhavesh Davda <bhavesh@vmware.com>
---
 examples/Makefile          |    1 +
 examples/txburst/Makefile  |   53 +++++++++
 examples/txburst/burst.c   |  221 +++++++++++++++++++++++++++++++++++
 examples/txburst/burst.h   |   55 +++++++++
 examples/txburst/txburst.c |  278 ++++++++++++++++++++++++++++++++++++++++++++
 examples/txburst/txburst.h |   40 +++++++
 6 files changed, 648 insertions(+), 0 deletions(-)
 create mode 100644 examples/txburst/Makefile
 create mode 100644 examples/txburst/burst.c
 create mode 100644 examples/txburst/burst.h
 create mode 100644 examples/txburst/txburst.c
 create mode 100644 examples/txburst/txburst.h
  

Comments

Thomas Monjalon Jan. 30, 2015, 10:33 a.m. UTC | #1
Hi Bhavesh,

2014-11-18 10:32, Bhavesh Davda:
> Test application to transmit 32-packet bursts of 220-byte UDP packets every
> 50 us, approximating 240,000 pps. We found it useful for testing hypervisor
> performance for a transmit-heavy but bursty workload in a VM with DPDK.
> 
> Signed-off-by: Bhavesh Davda <bhavesh@vmware.com>

There was no review of your patch.
Maybe you should explain why you think it should be integrated as an example.
What is new compared to other examples?

Thanks
  
Bhavesh Davda Jan. 30, 2015, 4:29 p.m. UTC | #2
Hi Thomas,

> Hi Bhavesh,
> 
> 2014-11-18 10:32, Bhavesh Davda:
> > Test application to transmit 32-packet bursts of 220-byte UDP packets
> every
> > 50 us, approximating 240,000 pps. We found it useful for testing
> hypervisor
> > performance for a transmit-heavy but bursty workload in a VM with
> DPDK.
> >
> > Signed-off-by: Bhavesh Davda <bhavesh@vmware.com>
> 
> There was no review of your patch.
> Maybe you should explain why you think it should be integrated as an
> example.
> What is new compared to other examples?

[Bhavesh Davda] Thanks for catching that. I was wondering why nobody responded.

I leave it up to you and the wider DPDK community to decide if this example is useful. It was useful to us (VMware) and a couple of partner companies in reproducing a packet drop on transmit issue at a telco/NFV operator lab more easily than setting up the DPDK-based VNF from the vendor along with a hardware load generator to generate the application-specific packet load. It was much easier to just run this example application in a VM to reproduce the packet drop issue.

What is different? I didn't find any other simple apps that only mimic Tx bursty behavior similar to this application. Maybe I missed some example application that has such a capability.

> 
> Thanks
> --
> Thomas
  
Thomas Monjalon Jan. 30, 2015, 4:43 p.m. UTC | #3
2015-01-30 16:29, Bhavesh Davda:
> Hi Thomas,
> 
> > Hi Bhavesh,
> > 
> > 2014-11-18 10:32, Bhavesh Davda:
> > > Test application to transmit 32-packet bursts of 220-byte UDP packets
> > every
> > > 50 us, approximating 240,000 pps. We found it useful for testing
> > hypervisor
> > > performance for a transmit-heavy but bursty workload in a VM with
> > DPDK.
> > >
> > > Signed-off-by: Bhavesh Davda <bhavesh@vmware.com>
> > 
> > There was no review of your patch.
> > Maybe you should explain why you think it should be integrated as an
> > example.
> > What is new compared to other examples?
> 
> [Bhavesh Davda] Thanks for catching that. I was wondering why nobody 
responded.
> 
> I leave it up to you and the wider DPDK community to decide if this example
> is useful. It was useful to us (VMware) and a couple of partner companies in
> reproducing a packet drop on transmit issue at a telco/NFV operator lab more
> easily than setting up the DPDK-based VNF from the vendor along with a
> hardware load generator to generate the application-specific packet load. It
> was much easier to just run this example application in a VM to reproduce
> the packet drop issue.
> 
> What is different? I didn't find any other simple apps that only mimic Tx
> bursty behavior similar to this application. Maybe I missed some example
> application that has such a capability.

Did you know pktgen-dpdk?
http://dpdk.org/browse/apps/pktgen-dpdk/tree/README.md

Do you think it could replace your application?
  
Bhavesh Davda Jan. 30, 2015, 4:48 p.m. UTC | #4
> Did you know pktgen-dpdk?
> http://dpdk.org/browse/apps/pktgen-dpdk/tree/README.md
> 
> Do you think it could replace your application?
> 

[Bhavesh Davda] Yes, I regularly use pktgen-dpdk, and love the app (thanks Keith!) but I couldn't quite get it to do this simplistic job of generating a stream of X-byte UDP packets in burst of Y spread apart by Z microseconds.
  
Wiles, Keith Jan. 30, 2015, 7:45 p.m. UTC | #5
Sent from my iPhone

On Jan 30, 2015, at 9:49 AM, Bhavesh Davda <bhavesh@vmware.com> wrote:

>> Did you know pktgen-dpdk?
>> http://dpdk.org/browse/apps/pktgen-dpdk/tree/README.md
>> 
>> Do you think it could replace your application?
> 
> [Bhavesh Davda] Yes, I regularly use pktgen-dpdk, and love the app (thanks Keith!) but I couldn't quite get it to do this simplistic job of generating a stream of X-byte UDP packets in burst of Y spread apart by Z microseconds.

Hmmm, sounds like an enhancement request to pktgen is needed here. I will look at adding it to pktgen and it is up to everyone if the example is reasonable to have. For me it does seem reasonable to include as it maybe simpler to setup, but if and when I can add that support to pktgen it may no longer be needed. 

Let me have a look at adding the support and will let you guys know next week.

Thanks Keith
  
Wiles, Keith Jan. 31, 2015, 11:47 p.m. UTC | #6
On 1/30/15, 1:45 PM, "Wiles, Keith" <keith.wiles@intel.com> wrote:

>
>
>Sent from my iPhone
>
>On Jan 30, 2015, at 9:49 AM, Bhavesh Davda <bhavesh@vmware.com> wrote:
>
>>> Did you know pktgen-dpdk?
>>> http://dpdk.org/browse/apps/pktgen-dpdk/tree/README.md
>>> 
>>> Do you think it could replace your application?
>> 
>> [Bhavesh Davda] Yes, I regularly use pktgen-dpdk, and love the app
>>(thanks Keith!) but I couldn't quite get it to do this simplistic job of
>>generating a stream of X-byte UDP packets in burst of Y spread apart by
>>Z microseconds.
>
>Hmmm, sounds like an enhancement request to pktgen is needed here. I will
>look at adding it to pktgen and it is up to everyone if the example is
>reasonable to have. For me it does seem reasonable to include as it maybe
>simpler to setup, but if and when I can add that support to pktgen it may
>no longer be needed.
>
>Let me have a look at adding the support and will let you guys know next
>week.

Looking at the txburst code and your description needing to send a burst
of 220 byte UDP packets with an interval of 50us is mostly doable via
Pktgen. In Pktgen you can setup a packet 220+UDP+other parameters already
in single packet mode or sequence mode. You can set the rate at a given
percentage per second of packets, but you can not set the interval rate
between burst easily. The number of packets in a burst is also adjustable
via the burst command ¹set <portlist> burst <value>'.

Did I describe the problem here correctly?

The current percentage rate is in whole numbers in Pktgen may not be fine
enough gain rate for some tests. I do have in Pktgen a way to adjust the
time between burst of packets using a debug command to fine tune the
number of clock ticks (HPET) to a given number ¹set <portlist> tx_cycles
<value>', would that command be useful and solve your given test case?

The tx_cycles option is not listed in the help text :-) Maybe I should
make it not hidden.

>
>Thanks Keith
  

Patch

diff --git a/examples/Makefile b/examples/Makefile
index 121dab4..12b10e1 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -62,6 +62,7 @@  DIRS-$(CONFIG_RTE_LIBRTE_METER) += qos_meter
 DIRS-$(CONFIG_RTE_LIBRTE_SCHED) += qos_sched
 DIRS-y += quota_watermark
 DIRS-y += timer
+DIRS-y += txburst
 DIRS-$(CONFIG_RTE_LIBRTE_VHOST) += vhost
 DIRS-$(CONFIG_RTE_LIBRTE_XEN_DOM0) += vhost_xen
 DIRS-y += vmdq
diff --git a/examples/txburst/Makefile b/examples/txburst/Makefile
new file mode 100644
index 0000000..38334f7
--- /dev/null
+++ b/examples/txburst/Makefile
@@ -0,0 +1,53 @@ 
+##########################################################
+# Copyright (C) 2014 VMware, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+##########################################################
+
+ifeq ($(RTE_SDK),)
+$(error "Please define RTE_SDK environment variable")
+endif
+
+# Default target, can be overriden by command line or environment
+RTE_TARGET ?= x86_64-default-linuxapp-gcc
+
+include $(RTE_SDK)/mk/rte.vars.mk
+
+# binary name
+APP = txburst
+
+# all source are stored in SRCS-y
+SRCS-y := txburst.c burst.c
+
+CFLAGS += $(WERROR_FLAGS)
+
+# workaround for a gcc bug with noreturn attribute
+# http://gcc.gnu.org/bugzilla/show_bug.cgi?id=12603
+ifeq ($(CONFIG_RTE_TOOLCHAIN_GCC),y)
+CFLAGS_main.o += -Wno-return-type
+endif
+
+EXTRA_CFLAGS += -O3 -g -Wfatal-errors
+
+include $(RTE_SDK)/mk/rte.extapp.mk
diff --git a/examples/txburst/burst.c b/examples/txburst/burst.c
new file mode 100644
index 0000000..dd682e8
--- /dev/null
+++ b/examples/txburst/burst.c
@@ -0,0 +1,221 @@ 
+/*********************************************************
+ * Copyright (C) 2014 VMware, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+#include <rte_byteorder.h>
+#include <rte_mbuf.h>
+#include <rte_memcpy.h>
+
+#include "burst.h"
+
+#define IP_DEFTTL  64   /* from RFC 1340. */
+#define IP_VERSION 0x40
+#define IP_HDRLEN  0x05 /* default IP header length == five 32-bits words. */
+#define IP_VHL_DEF (IP_VERSION | IP_HDRLEN)
+
+static void
+copy_buf_to_pkt_segs(void *buf, unsigned len, struct rte_mbuf *pkt,
+		unsigned offset)
+{
+	struct rte_mbuf *seg;
+	void *seg_buf;
+	unsigned copy_len;
+
+	seg = pkt;
+	while (offset >= seg->data_len) {
+		offset -= seg->data_len;
+		seg = seg->next;
+	}
+	copy_len = seg->data_len - offset;
+	seg_buf = rte_pktmbuf_mtod(seg, char *) + offset;
+	while (len > copy_len) {
+		rte_memcpy(seg_buf, buf, (size_t) copy_len);
+		len -= copy_len;
+		buf = ((char *) buf + copy_len);
+		seg = seg->next;
+		seg_buf = rte_pktmbuf_mtod(seg, void *);
+	}
+	rte_memcpy(seg_buf, buf, (size_t) len);
+}
+
+static inline void
+copy_buf_to_pkt(void *buf, unsigned len, struct rte_mbuf *pkt, unsigned offset)
+{
+	if (offset + len <= pkt->data_len) {
+		rte_memcpy(rte_pktmbuf_mtod(pkt, char *) + offset,
+				buf, (size_t) len);
+		return;
+	}
+	copy_buf_to_pkt_segs(buf, len, pkt, offset);
+}
+
+
+uint16_t
+initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
+		uint16_t dst_port, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct udp_hdr));
+
+	udp_hdr->src_port = rte_cpu_to_be_16(src_port);
+	udp_hdr->dst_port = rte_cpu_to_be_16(dst_port);
+	udp_hdr->dgram_len = rte_cpu_to_be_16(pkt_len);
+	udp_hdr->dgram_cksum = 0; /* No UDP checksum. */
+
+	return pkt_len;
+}
+
+
+uint16_t
+initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+		uint32_t dst_addr, uint16_t pkt_data_len)
+{
+	uint16_t pkt_len;
+	uint16_t *ptr16;
+	uint32_t ip_cksum;
+
+	/*
+	 * Initialize IP header.
+	 */
+	pkt_len = (uint16_t) (pkt_data_len + sizeof(struct ipv4_hdr));
+
+	ip_hdr->version_ihl   = IP_VHL_DEF;
+	ip_hdr->type_of_service   = 0;
+	ip_hdr->fragment_offset = 0;
+	ip_hdr->time_to_live   = IP_DEFTTL;
+	ip_hdr->next_proto_id = IPPROTO_UDP;
+	ip_hdr->packet_id = 0;
+	ip_hdr->total_length   = rte_cpu_to_be_16(pkt_len);
+	ip_hdr->src_addr = rte_cpu_to_be_32(src_addr);
+	ip_hdr->dst_addr = rte_cpu_to_be_32(dst_addr);
+
+	/*
+	 * Compute IP header checksum.
+	 */
+	ptr16 = (uint16_t *)ip_hdr;
+	ip_cksum = 0;
+	ip_cksum += ptr16[0]; ip_cksum += ptr16[1];
+	ip_cksum += ptr16[2]; ip_cksum += ptr16[3];
+	ip_cksum += ptr16[4];
+	ip_cksum += ptr16[6]; ip_cksum += ptr16[7];
+	ip_cksum += ptr16[8]; ip_cksum += ptr16[9];
+
+	/*
+	 * Reduce 32 bit checksum to 16 bits and complement it.
+	 */
+	ip_cksum = ((ip_cksum & 0xFFFF0000) >> 16) +
+		(ip_cksum & 0x0000FFFF);
+	ip_cksum %= 65536;
+	ip_cksum = (~ip_cksum) & 0x0000FFFF;
+	if (ip_cksum == 0)
+		ip_cksum = 0xFFFF;
+	ip_hdr->hdr_checksum = (uint16_t) ip_cksum;
+
+	return pkt_len;
+}
+
+
+
+/*
+ * The maximum number of segments per packet is used when creating
+ * scattered transmit packets composed of a list of mbufs.
+ */
+#define RTE_MAX_SEGS_PER_PKT 255 /**< pkt.nb_segs is a 8-bit unsigned char. */
+
+#define TXONLY_DEF_PACKET_LEN 64
+#define TXONLY_DEF_PACKET_LEN_220 220
+
+uint16_t tx_pkt_length = TXONLY_DEF_PACKET_LEN;
+uint16_t tx_pkt_seg_lengths[RTE_MAX_SEGS_PER_PKT] = {
+		TXONLY_DEF_PACKET_LEN_220,
+};
+
+uint8_t  tx_pkt_nb_segs = 1;
+
+int
+generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
+		struct ether_hdr *eth_hdr, void *ip_hdr,
+		struct udp_hdr *udp_hdr, int nb_pkt_per_burst)
+{
+	int i, nb_pkt = 0;
+	size_t eth_hdr_size;
+
+	struct rte_mbuf *pkt_seg;
+	struct rte_mbuf *pkt;
+
+	for (nb_pkt = 0; nb_pkt < nb_pkt_per_burst; nb_pkt++) {
+		pkt = rte_pktmbuf_alloc(mp);
+		if (pkt == NULL) {
+nomore_mbuf:
+			if (nb_pkt == 0)
+				return -1;
+			break;
+		}
+
+		pkt->data_len = tx_pkt_seg_lengths[0];
+		pkt_seg = pkt;
+		for (i = 1; i < tx_pkt_nb_segs; i++) {
+			pkt_seg->next = rte_pktmbuf_alloc(mp);
+			if (pkt_seg->next == NULL) {
+				pkt->nb_segs = i;
+				rte_pktmbuf_free(pkt);
+				goto nomore_mbuf;
+			}
+			pkt_seg = pkt_seg->next;
+			pkt_seg->data_len = tx_pkt_seg_lengths[i];
+		}
+		pkt_seg->next = NULL; /* Last segment of packet. */
+
+		/*
+		 * Copy headers in first packet segment(s).
+		 */
+		eth_hdr_size = sizeof(struct ether_hdr);
+
+		copy_buf_to_pkt(eth_hdr, eth_hdr_size, pkt, 0);
+
+		copy_buf_to_pkt(ip_hdr, sizeof(struct ipv4_hdr), pkt,
+			eth_hdr_size);
+		copy_buf_to_pkt(udp_hdr, sizeof(*udp_hdr), pkt,
+			eth_hdr_size + sizeof(struct ipv4_hdr));
+
+		/*
+		 * Complete first mbuf of packet and append it to the
+		 * burst of packets to be transmitted.
+		 */
+		pkt->nb_segs = tx_pkt_nb_segs;
+		pkt->pkt_len = tx_pkt_length;
+		pkt->l2_len = eth_hdr_size;
+
+		pkt->vlan_tci  = ETHER_TYPE_IPv4;
+		pkt->l3_len = sizeof(struct ipv4_hdr);
+		pkt->ol_flags = PKT_RX_IPV4_HDR;
+
+		pkts_burst[nb_pkt] = pkt;
+	}
+
+	return nb_pkt;
+}
diff --git a/examples/txburst/burst.h b/examples/txburst/burst.h
new file mode 100644
index 0000000..760c30f
--- /dev/null
+++ b/examples/txburst/burst.h
@@ -0,0 +1,55 @@ 
+/*********************************************************
+ * Copyright (C) 2014 VMware, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+#ifndef PACKET_BURST_GENERATOR_H_
+#define PACKET_BURST_GENERATOR_H_
+
+#include <rte_mbuf.h>
+#include <rte_ether.h>
+#include <rte_ip.h>
+#include <rte_udp.h>
+
+
+#define IPV4_ADDR(a, b, c, d)(((a & 0xff) << 24) | ((b & 0xff) << 16) | \
+		((c & 0xff) << 8) | (d & 0xff))
+
+
+uint16_t
+initialize_udp_header(struct udp_hdr *udp_hdr, uint16_t src_port,
+		uint16_t dst_port, uint16_t pkt_data_len);
+
+
+uint16_t
+initialize_ipv4_header(struct ipv4_hdr *ip_hdr, uint32_t src_addr,
+		uint32_t dst_addr, uint16_t pkt_data_len);
+
+int
+generate_packet_burst(struct rte_mempool *mp, struct rte_mbuf **pkts_burst,
+		struct ether_hdr *eth_hdr, void *ip_hdr,
+		struct udp_hdr *udp_hdr, int nb_pkt_per_burst);
+
+#endif /* PACKET_BURST_GENERATOR_H_ */
diff --git a/examples/txburst/txburst.c b/examples/txburst/txburst.c
new file mode 100644
index 0000000..dbcb831
--- /dev/null
+++ b/examples/txburst/txburst.c
@@ -0,0 +1,278 @@ 
+/*********************************************************
+ * Copyright (C) 2014 VMware, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+#include <stdint.h>
+#include <inttypes.h>
+#include <time.h>
+#include <sys/time.h>
+#include <rte_eal.h>
+#include <rte_ethdev.h>
+#include <rte_cycles.h>
+#include <rte_lcore.h>
+#include <rte_mbuf.h>
+#include <rte_byteorder.h>
+#include "txburst.h"
+#include "burst.h"
+
+#define RX_RING_SIZE 128
+#define RX_FREE_THRESH 32
+#define RX_PTHRESH 8
+#define RX_HTHRESH 8
+#define RX_WTHRESH 0
+
+#define TX_RING_SIZE 512
+#define TX_FREE_THRESH 32
+#define TX_PTHRESH 32
+#define TX_HTHRESH 0
+#define TX_WTHRESH 0
+#define TX_RSBIT_THRESH 32
+#define TX_Q_FLAGS (ETH_TXQ_FLAGS_NOMULTSEGS | ETH_TXQ_FLAGS_NOVLANOFFL |\
+	ETH_TXQ_FLAGS_NOXSUMSCTP | ETH_TXQ_FLAGS_NOXSUMUDP | \
+	ETH_TXQ_FLAGS_NOXSUMTCP)
+
+#define NUM_MBUFS 8191
+#define MBUF_SIZE (2048 + sizeof(struct rte_mbuf) + RTE_PKTMBUF_HEADROOM)
+#define MBUF_CACHE_SIZE 250
+#define BURST_SIZE 32
+
+static struct rte_eth_conf port_conf_default = {
+	.rxmode = {
+		.mq_mode = ETH_MQ_RX_NONE,
+		.max_rx_pkt_len = ETHER_MAX_LEN,
+		.split_hdr_size = 0,
+		.header_split   = 0, /**< Header Split disabled */
+		.hw_ip_checksum = 0, /**< IP checksum offload enabled */
+		.hw_vlan_filter = 0, /**< VLAN filtering disabled */
+		.jumbo_frame    = 0, /**< Jumbo Frame Support disabled */
+		.hw_strip_crc   = 0, /**< CRC stripped by hardware */
+	},
+	.txmode = {
+		.mq_mode = ETH_MQ_TX_NONE,
+	},
+	.lpbk_mode = 0,
+};
+
+static const struct rte_eth_rxconf rx_conf_default = {
+	.rx_thresh = {
+		.pthresh = RX_PTHRESH,
+		.hthresh = RX_HTHRESH,
+		.wthresh = RX_WTHRESH,
+	},
+	.rx_free_thresh = RX_FREE_THRESH,
+	.rx_drop_en = 0,
+};
+
+static struct rte_eth_txconf tx_conf_default = {
+	.tx_thresh = {
+		.pthresh = TX_PTHRESH,
+		.hthresh = TX_HTHRESH,
+		.wthresh = TX_WTHRESH,
+	},
+	.tx_free_thresh = TX_FREE_THRESH,
+	.tx_rs_thresh = TX_RSBIT_THRESH,
+	.txq_flags = TX_Q_FLAGS
+
+};
+
+static struct rte_mbuf *mbufs[2][BURST_SIZE * 100];
+static uint32_t src_addr = IPV4_ADDR(192, 168, 1, 98);
+static uint32_t dst_addr = IPV4_ADDR(192, 168, 1, 99);
+
+static struct timespec tv = {
+	.tv_sec = 0,
+	.tv_nsec = 50000		/* 50 us */
+};
+
+/*
+ * Initialises a given port using global settings and with the rx buffers
+ * coming from the mbuf_pool passed as parameter
+ */
+static inline int
+port_init(uint8_t port, struct rte_mempool *mbuf_pool)
+{
+	struct rte_eth_conf port_conf = port_conf_default;
+	const uint16_t rxRings = 1, txRings = 1;
+	int retval;
+	uint16_t q;
+
+	if (port >= rte_eth_dev_count())
+		return -1;
+
+	retval = rte_eth_dev_configure(port, rxRings, txRings, &port_conf);
+	if (retval != 0)
+		return retval;
+
+	for (q = 0; q < rxRings; q++) {
+		retval = rte_eth_rx_queue_setup(port, q, RX_RING_SIZE,
+				rte_eth_dev_socket_id(port), &rx_conf_default,
+				mbuf_pool);
+		if (retval < 0)
+			return retval;
+	}
+
+	for (q = 0; q < txRings; q++) {
+		retval = rte_eth_tx_queue_setup(port, q, TX_RING_SIZE,
+				rte_eth_dev_socket_id(port), &tx_conf_default);
+		if (retval < 0)
+			return retval;
+	}
+
+	retval  = rte_eth_dev_start(port);
+	if (retval < 0)
+		return retval;
+
+	struct ether_addr addr;
+
+	rte_eth_macaddr_get(port, &addr);
+	printf("Port %u MAC: %02"PRIx8" %02"PRIx8" %02"PRIx8
+			" %02"PRIx8" %02"PRIx8" %02"PRIx8"\n",
+			(unsigned)port,
+			addr.addr_bytes[0], addr.addr_bytes[1],
+			addr.addr_bytes[2], addr.addr_bytes[3],
+			addr.addr_bytes[4], addr.addr_bytes[5]);
+
+	struct ether_hdr eth_hdr;
+
+	eth_hdr.s_addr = addr;
+	addr.addr_bytes[5] ^= 1;
+	eth_hdr.d_addr = addr;
+	eth_hdr.ether_type = rte_cpu_to_be_16(ETHER_TYPE_IPv4);
+
+	int pkt_len;
+	struct udp_hdr udp_hdr;
+	struct ipv4_hdr ip_hdr;
+
+	pkt_len = initialize_udp_header(&udp_hdr, 0x0246, 0x0357, 174);
+	pkt_len = initialize_ipv4_header(&ip_hdr, src_addr, dst_addr, pkt_len);
+
+	int num_pkts;
+
+	num_pkts = generate_packet_burst(mbuf_pool, &mbufs[port][0],
+			&eth_hdr, &ip_hdr,
+			&udp_hdr, BURST_SIZE * 100);
+
+	if (num_pkts < BURST_SIZE * 100)
+		rte_exit(EXIT_FAILURE, "Cannot allocate packet bursts\n");
+
+	return 0;
+}
+
+/*
+ * Main thread that does the work, reading from INPUT_PORT
+ * and writing to OUTPUT_PORT
+ */
+static  __attribute__((noreturn)) void
+lcore_main(void)
+{
+	const uint8_t nb_ports = rte_eth_dev_count();
+	uint8_t port;
+	int burst_cycle = 0;
+	unsigned long pktsTxed = 0;
+	struct timeval tvStart, tvEnd, tvDiff, tvLastDrop, tvNow;
+	struct timespec tvrem;
+
+	printf("\nCore %u transmitting packets. [Ctrl+C to quit]\n",
+			rte_lcore_id());
+	gettimeofday(&tvStart, NULL);
+	tvLastDrop = tvStart;
+	for (;;) {
+		for (port = 0; port < nb_ports; port++) {
+			const uint16_t nb_tx = rte_eth_tx_burst(port, 0,
+					&mbufs[port]
+					[(burst_cycle % 100) * BURST_SIZE],
+					BURST_SIZE);
+			pktsTxed += nb_tx;
+			if (unlikely(nb_tx < BURST_SIZE)) {
+				gettimeofday(&tvNow, NULL);
+				timersub(&tvNow, &tvLastDrop, &tvDiff);
+				printf("Port %d dropped %d (Time since last "
+					"drop %g s)\n", port,
+					BURST_SIZE - nb_tx, tvDiff.tv_sec +
+					tvDiff.tv_usec/1000000.0);
+				tvLastDrop = tvNow;
+			}
+		}
+		burst_cycle++;
+		if (burst_cycle % 50000 == 0) {
+			gettimeofday(&tvEnd, NULL);
+			timersub(&tvEnd, &tvStart, &tvDiff);
+			printf("%g pps...",
+				pktsTxed / (tvDiff.tv_sec + tvDiff.tv_usec/1000000.0));
+			if (burst_cycle % 500000 == 0)
+				printf("\n");
+			fflush(stdout);
+			pktsTxed = 0;
+			tvStart = tvEnd;
+		}
+		tvrem = tv;
+		while (nanosleep(&tvrem, &tvrem) != 0)
+			;
+	}
+}
+
+/* Main function, does initialisation and calls the per-lcore functions */
+int
+MAIN(int argc, char *argv[])
+{
+	struct rte_mempool *mbuf_pool;
+	unsigned nb_ports;
+	uint8_t portid;
+
+	/* init EAL */
+	int ret = rte_eal_init(argc, argv);
+
+	if (ret < 0)
+		rte_exit(EXIT_FAILURE, "Error with EAL initialization\n");
+	argc -= ret;
+	argv += ret;
+
+	nb_ports = rte_eth_dev_count();
+	if (nb_ports > 2)
+		rte_exit(EXIT_FAILURE, "Error: number of ports must be <=2\n");
+
+	mbuf_pool = rte_mempool_create("MBUF_POOL", NUM_MBUFS * nb_ports,
+				       MBUF_SIZE, MBUF_CACHE_SIZE,
+				       sizeof(struct rte_pktmbuf_pool_private),
+				       rte_pktmbuf_pool_init, NULL,
+				       rte_pktmbuf_init, NULL,
+				       rte_socket_id(), 0);
+	if (mbuf_pool == NULL)
+		rte_exit(EXIT_FAILURE, "Cannot create mbuf pool\n");
+
+	/* initialize all ports */
+	for (portid = 0; portid < nb_ports; portid++)
+		if (port_init(portid, mbuf_pool) != 0)
+			rte_exit(EXIT_FAILURE, "Cannot init port %"PRIu8"\n",
+					portid);
+
+	if (rte_lcore_count() > 1)
+		printf("\nWARNING: Coremask too big - App uses only 1 lcore\n");
+
+	/* call lcore_main on master core only */
+	lcore_main();
+	return 0;
+}
diff --git a/examples/txburst/txburst.h b/examples/txburst/txburst.h
new file mode 100644
index 0000000..909dd3b
--- /dev/null
+++ b/examples/txburst/txburst.h
@@ -0,0 +1,40 @@ 
+/*********************************************************
+ * Copyright (C) 2014 VMware, Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *********************************************************/
+
+#ifndef _MAIN_H_
+#define _MAIN_H_
+
+
+#ifdef RTE_EXEC_ENV_BAREMETAL
+#define MAIN _main
+#else
+#define MAIN main
+#endif
+
+int MAIN(int argc, char *argv[]);
+
+#endif /* ifndef _MAIN_H_ */